From 2e91cd63757bc5142f54e40393ff993e2041310c Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Tue, 11 Nov 2025 19:08:03 +0000 Subject: [PATCH 01/13] Use internal release of package --- package-lock.json | 23 +++++++++++++++++++++++ package.json | 1 + 2 files changed, 24 insertions(+) diff --git a/package-lock.json b/package-lock.json index a264ede1..2baa630b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "gulp-sass": "^6.0.1", "lodash": "^4.17.21", "nhsuk-frontend": "^10.0.0", + "nhsuk-prototype-kit": "8.0.0-internal.0", "nunjucks": "^3.2.4", "path": "^0.12.7", "plugin-error": "^2.0.1", @@ -12461,6 +12462,28 @@ "node": "^20.9.0 || ^22.11.0" } }, + "node_modules/nhsuk-prototype-kit": { + "version": "8.0.0-internal.0", + "resolved": "https://registry.npmjs.org/nhsuk-prototype-kit/-/nhsuk-prototype-kit-8.0.0-internal.0.tgz", + "integrity": "sha512-YmHdPnL1d8LiDD2SORVVMZpkwqPFfvelapTMjX9f+66IXDQZ/tyBSbIaPmJlhYg+8HnVnRzJEgJGCUGk88samg==", + "license": "MIT", + "workspaces": [ + ".", + "testapp" + ], + "dependencies": { + "body-parser": "^2.2.0", + "cookie-parser": "^1.4.7", + "express-session": "^1.18.1" + }, + "engines": { + "node": "^20.13.0 || ^22.11.0 || ^24.11.0" + }, + "peerDependencies": { + "express": "^5.0", + "nhsuk-frontend": "^10.0" + } + }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", diff --git a/package.json b/package.json index 2a6354c3..f168bdfd 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "gulp-sass": "^6.0.1", "lodash": "^4.17.21", "nhsuk-frontend": "^10.0.0", + "nhsuk-prototype-kit": "8.0.0-internal.0", "nunjucks": "^3.2.4", "path": "^0.12.7", "plugin-error": "^2.0.1", From c156434de0d4def39bed28934f738942ad755f1b Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Tue, 11 Nov 2025 19:26:05 +0000 Subject: [PATCH 02/13] Remove dependencies These have been added to the `nhsuk-prototype-kit` package instead, so can be managed there. --- package-lock.json | 87 ----------------------------------------------- package.json | 7 ---- 2 files changed, 94 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2baa630b..3becc923 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,15 +14,10 @@ "@babel/preset-env": "^7.28.3", "@faker-js/faker": "^10.0.0", "@inquirer/prompts": "^7.8.4", - "body-parser": "^2.2.0", "browser-sync": "^3.0.4", - "client-sessions": "^0.8.0", "connect-flash": "^0.1.1", - "cookie-parser": "^1.4.7", "dayjs": "^1.11.15", - "dotenv": "^17.2.1", "express": "^5.1.0", - "express-session": "^1.18.2", "gulp": "^5.0.1", "gulp-babel": "^8.0.0", "gulp-clean": "^0.4.0", @@ -30,11 +25,9 @@ "gulp-nodemon": "^2.5.0", "gulp-rename": "^2.1.0", "gulp-sass": "^6.0.1", - "lodash": "^4.17.21", "nhsuk-frontend": "^10.0.0", "nhsuk-prototype-kit": "8.0.0-internal.0", "nunjucks": "^3.2.4", - "path": "^0.12.7", "plugin-error": "^2.0.1", "pluralize": "^8.0.0", "portscanner": "^2.2.0", @@ -5388,18 +5381,6 @@ "node": ">= 12" } }, - "node_modules/client-sessions": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/client-sessions/-/client-sessions-0.8.0.tgz", - "integrity": "sha512-XERL6B5cJYGEaAigTADRr8NrUhkGmIUdrlHBzRM62uZEtFben5QYbaOxgWX79wFbCIvABhgZCWch1glw2fcyiQ==", - "license": "MPL-2.0", - "dependencies": { - "cookies": "^0.7.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -5713,19 +5694,6 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, - "node_modules/cookies": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.3.tgz", - "integrity": "sha512-+gixgxYSgQLTaTIilDHAdlNPZDENDQernEMiIcZpYYP14zgHsCt4Ce1FEjFtcp6GefhozebB6orvhAAWx/IS0A==", - "license": "MIT", - "dependencies": { - "depd": "~1.1.2", - "keygrip": "~1.0.3" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", @@ -6086,18 +6054,6 @@ "node": ">=6.0.0" } }, - "node_modules/dotenv": { - "version": "17.2.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", - "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", - "license": "BSD-2-Clause", - "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", @@ -11643,15 +11599,6 @@ "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", "license": "MIT" }, - "node_modules/keygrip": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.3.tgz", - "integrity": "sha512-/PpesirAIfaklxUzp4Yb7xBper9MwP6hNRA6BGGUFCgbJ+BM5CKBtsoxinNXkLHAr+GXS1/lSlF2rP7cv5Fl+g==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -13139,16 +13086,6 @@ "node": ">=0.10.0" } }, - "node_modules/path": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", - "license": "MIT", - "dependencies": { - "process": "^0.11.1", - "util": "^0.10.3" - } - }, "node_modules/path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", @@ -13502,15 +13439,6 @@ "node": ">= 0.8" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -16979,27 +16907,12 @@ "node": ">=0.10.0" } }, - "node_modules/util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", - "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", - "license": "MIT", - "dependencies": { - "inherits": "2.0.3" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, - "node_modules/util/node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", - "license": "ISC" - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/package.json b/package.json index f168bdfd..d8a663f5 100644 --- a/package.json +++ b/package.json @@ -24,15 +24,10 @@ "@babel/preset-env": "^7.28.3", "@faker-js/faker": "^10.0.0", "@inquirer/prompts": "^7.8.4", - "body-parser": "^2.2.0", "browser-sync": "^3.0.4", - "client-sessions": "^0.8.0", "connect-flash": "^0.1.1", - "cookie-parser": "^1.4.7", "dayjs": "^1.11.15", - "dotenv": "^17.2.1", "express": "^5.1.0", - "express-session": "^1.18.2", "gulp": "^5.0.1", "gulp-babel": "^8.0.0", "gulp-clean": "^0.4.0", @@ -40,11 +35,9 @@ "gulp-nodemon": "^2.5.0", "gulp-rename": "^2.1.0", "gulp-sass": "^6.0.1", - "lodash": "^4.17.21", "nhsuk-frontend": "^10.0.0", "nhsuk-prototype-kit": "8.0.0-internal.0", "nunjucks": "^3.2.4", - "path": "^0.12.7", "plugin-error": "^2.0.1", "pluralize": "^8.0.0", "portscanner": "^2.2.0", From 01d66eeb35763f58a79fc5d7016ac62ff2ee9b38 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Tue, 11 Nov 2025 19:32:11 +0000 Subject: [PATCH 03/13] Update app.js --- app.js | 263 ++------------------------------------------------------- 1 file changed, 9 insertions(+), 254 deletions(-) diff --git a/app.js b/app.js index 4a421f4e..2ac2d1c1 100755 --- a/app.js +++ b/app.js @@ -1,73 +1,35 @@ -// Core dependencies -const { - createReadStream, - createWriteStream, - existsSync, - mkdirSync, - readdirSync, - unlinkSync -} = require('node:fs') const { join } = require('node:path') const { format: urlFormat } = require('node:url') // External dependencies -const bodyParser = require('body-parser') -const sessionInCookie = require('client-sessions') const flash = require('connect-flash') -const cookieParser = require('cookie-parser') -const dotenv = require('dotenv') const express = require('express') -const sessionInMemory = require('express-session') const nunjucks = require('nunjucks') -const sessionInFiles = require('session-file-store') -// Run before other code to make sure variables from .env are available -dotenv.config({ - quiet: true -}) +const NHSPrototypeKit = require('nhsuk-prototype-kit') // Local dependencies const config = require('./app/config') const locals = require('./app/locals') const routes = require('./app/routes') -const exampleTemplatesRoutes = require('./lib/example_templates_routes') -const authentication = require('./lib/middleware/authentication') -const automaticRouting = require('./lib/middleware/auto-routing') -const production = require('./lib/middleware/production') -const prototypeAdminRoutes = require('./lib/middleware/prototype-admin-routes') +const sessionDataDefaults = require('./app/data/session-data-defaults') const utils = require('./lib/utils') -const packageInfo = require('./package.json') // Set configuration variables const port = parseInt(process.env.PORT || config.port, 10) || 2000 // Initialise applications const app = express() -const exampleTemplatesApp = express() - -// Set up configuration variables -const useAutoStoreData = - process.env.USE_AUTO_STORE_DATA || config.useAutoStoreData -const useCookieSessionStore = - process.env.USE_COOKIE_SESSION_STORE || config.useCookieSessionStore // Add variables that are available in all views app.locals.asset_path = '/public/' -app.locals.useAutoStoreData = useAutoStoreData === 'true' -app.locals.useCookieSessionStore = useCookieSessionStore === 'true' app.locals.serviceName = config.serviceName -// Use cookie middleware to parse cookies -app.use(cookieParser()) - // Nunjucks configuration for application const appViews = [ join(__dirname, 'app/views/'), join(__dirname, 'app/views/_templates'), join(__dirname, 'app/views/_includes'), - join(__dirname, 'lib/example-templates/'), - join(__dirname, 'lib/prototype-admin/'), - join(__dirname, 'lib/templates/'), join(__dirname, 'node_modules/nhsuk-frontend/dist/nhsuk/components'), join(__dirname, 'node_modules/nhsuk-frontend/dist/nhsuk/macros'), join(__dirname, 'node_modules/nhsuk-frontend/dist/nhsuk'), @@ -85,176 +47,10 @@ const nunjucksConfig = { nunjucksConfig.express = app let nunjucksAppEnv = nunjucks.configure(appViews, nunjucksConfig) -nunjucksAppEnv.addGlobal('version', packageInfo.version) - -// Add Nunjucks filters -utils.addNunjucksFilters(nunjucksAppEnv) - -// Session uses service name to avoid clashes with other prototypes -const sessionName = `nhsuk-prototype-kit-${Buffer.from(config.serviceName, 'utf8').toString('hex')}` -const sessionOptions = { - secret: sessionName, - cookie: { - maxAge: 1000 * 60 * 60 * 4 // 4 hours - } -} - -if (process.env.NODE_ENV === 'production') { - app.use(production) - app.use(authentication) -} - -// Support session data in cookie or memory -if (useCookieSessionStore === 'true') { - app.use( - sessionInCookie({ - ...sessionOptions, - cookieName: sessionName, - proxy: true, - requestKey: 'session' - }) - ) -} else { - // app.use( - // sessionInMemory({ - // ...sessionOptions, - // name: sessionName, - // resave: false, - // saveUninitialized: false - // }) - // ) - - // Somewhat similar file store to GOV.UK - const FileStore = sessionInFiles(sessionInMemory) - const sessionPath = join(__dirname, '.tmp/sessions') - - // Make sure the sessions directory exists - if (!existsSync(sessionPath)) { - mkdirSync(sessionPath, { recursive: true }) - } else { - // Clear existing session files on restart - readdirSync(sessionPath).forEach((file) => { - unlinkSync(join(sessionPath, file)) - }) - } - - // app.use( - // sessionInMemory({ - // ...sessionOptions, - // name: sessionName, - // resave: false, - // saveUninitialized: false, - // store: new FileStore({ - // path: sessionPath, - // logFn: (message) => { - // // Suppress all expected session-related messages - // if ( - // message.endsWith('Deleting expired sessions') || - // message.includes('ENOENT') - // ) { - // return - // } - // // Only log unexpected issues - // console.log(message) - // } - // }) - // }) - // ) - // Support session data in cookie or memory - if (useCookieSessionStore === 'true') { - app.use( - sessionInCookie({ - ...sessionOptions, - cookieName: sessionName, - proxy: true, - requestKey: 'session' - }) - ) - } else { - app.use( - sessionInMemory({ - ...sessionOptions, - name: sessionName, - resave: false, - saveUninitialized: false - }) - ) - } -} - -// Support for parsing data in POSTs -app.use(bodyParser.json()) -app.use( - bodyParser.urlencoded({ - extended: true - }) -) - -// Automatically store all data users enter -if (useAutoStoreData === 'true') { - app.use(utils.autoStoreData) - utils.addCheckedFunction(nunjucksAppEnv) -} - -app.use(utils.setLocals) // Flash messages app.use(flash()) -// Warn if node_modules folder doesn't exist -function checkFiles() { - const nodeModulesExists = existsSync(join(__dirname, '/node_modules')) - if (!nodeModulesExists) { - throw new Error( - 'ERROR: Node module folder missing. Try running `npm install`' - ) - } - - // Create template .env file if it doesn't exist - const envExists = existsSync(join(__dirname, '/.env')) - if (!envExists) { - createReadStream(join(__dirname, '/lib/template.env')).pipe( - createWriteStream(join(__dirname, '/.env')) - ) - } -} - -// initial checks -checkFiles() - -// Create template session data defaults file if it doesn't exist -const dataDirectory = join(__dirname, '/app/data') -const sessionDataDefaultsFile = join(dataDirectory, '/session-data-defaults.js') -const sessionDataDefaultsFileExists = existsSync(sessionDataDefaultsFile) - -if (!sessionDataDefaultsFileExists) { - console.log('Creating session data defaults file') - if (!existsSync(dataDirectory)) { - mkdirSync(dataDirectory) - } - - createReadStream( - join(__dirname, '/lib/template.session-data-defaults.js') - ).pipe(createWriteStream(sessionDataDefaultsFile)) -} - -// Local variables -app.use(locals(config)) - -// View engine -app.set('view engine', 'html') -exampleTemplatesApp.set('view engine', 'html') - -// Support for parsing nested query strings -// https://github.com/nhsuk/nhsuk-prototype-kit/issues/644 -app.set('query parser', 'extended') - -// This setting trusts the X-Forwarded headers set by -// a proxy and uses them to set the standard header in -// req. This is needed for hosts like Heroku. -// See https://expressjs.com/en/guide/behind-proxies.html -app.set('trust proxy', 1) - // Use public folder for static assets app.use(express.static(join(__dirname, 'public'))) @@ -264,57 +60,16 @@ app.use( express.static(join(__dirname, 'node_modules/nhsuk-frontend/dist/nhsuk')) ) -// Use custom application routes -app.use('/', routes) - -// Automatically route pages -app.get(/^([^.]+)$/, (req, res, next) => { - automaticRouting.matchRoutes(req, res, next) -}) - -// Example template routes -app.use('/example-templates', exampleTemplatesApp) - -nunjucksAppEnv = nunjucks.configure(appViews, { - autoescape: true, - express: exampleTemplatesApp -}) -nunjucksAppEnv.addGlobal('version', packageInfo.version) - // Add Nunjucks filters utils.addNunjucksFilters(nunjucksAppEnv) -exampleTemplatesApp.use('/', exampleTemplatesRoutes) - -// Automatically route example template pages -exampleTemplatesApp.get(/^([^.]+)$/, (req, res, next) => { - automaticRouting.matchRoutes(req, res, next) -}) - -app.use('/prototype-admin', prototypeAdminRoutes) - -// Redirect all POSTs to GETs - this allows users to use POST for autoStoreData -app.post(/^\/([^.]+)$/, (req, res) => { - res.redirect( - urlFormat({ - pathname: `/${req.params[0]}`, - query: req.query - }) - ) -}) - -// Catch 404 and forward to error handler -app.use((req, res, next) => { - const err = new Error(`Page not found: ${req.path}`) - err.status = 404 - next(err) -}) - -// Display error -app.use((err, req, res) => { - console.error(err.message) - res.status(err.status || 500) - res.send(err.message) +NHSPrototypeKit.init({ + serviceName: config.serviceName, + express: app, + nunjucks: nunjucksAppEnv, + routes: routes, + locals: locals, + sessionDataDefaults: sessionDataDefaults }) // Run the application From 24032a3df7597b8ef269a620257bafed0a4fd0a8 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Tue, 11 Nov 2025 19:32:41 +0000 Subject: [PATCH 04/13] Update locals --- app/locals.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/locals.js b/app/locals.js index 248b04b4..34469e97 100644 --- a/app/locals.js +++ b/app/locals.js @@ -1,8 +1,7 @@ // app/locals.js -module.exports = (config) => (req, res, next) => { +module.exports = (req, res, next) => { const locals = { - serviceName: config.serviceName, currentUrl: req.path, flash: req.flash(), query: req.query, From fa281c0b6fbfa305aedbe0adfaf2d5aa0da7cdd9 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Tue, 11 Nov 2025 19:40:44 +0000 Subject: [PATCH 05/13] add filters directly --- app.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 2ac2d1c1..e248a3f2 100755 --- a/app.js +++ b/app.js @@ -13,7 +13,7 @@ const config = require('./app/config') const locals = require('./app/locals') const routes = require('./app/routes') const sessionDataDefaults = require('./app/data/session-data-defaults') -const utils = require('./lib/utils') +const filters = require('./app/filters') // Set configuration variables const port = parseInt(process.env.PORT || config.port, 10) || 2000 @@ -61,7 +61,12 @@ app.use( ) // Add Nunjucks filters -utils.addNunjucksFilters(nunjucksAppEnv) +for (const [name, filter] of Object.entries(filters())) { + nunjucksAppEnv.addFilter(name, filter) + + // Duplicate filter as global function + nunjucksAppEnv.addGlobal(name, filter) +} NHSPrototypeKit.init({ serviceName: config.serviceName, From 52b140b22fdf46782932d13c4cf6825e540c5681 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Tue, 11 Nov 2025 19:44:05 +0000 Subject: [PATCH 06/13] Move find-available-port --- {lib/utils => app}/find-available-port.js | 0 gulpfile.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename {lib/utils => app}/find-available-port.js (100%) diff --git a/lib/utils/find-available-port.js b/app/find-available-port.js similarity index 100% rename from lib/utils/find-available-port.js rename to app/find-available-port.js diff --git a/gulpfile.js b/gulpfile.js index 8e60b8a7..17a513a4 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -10,7 +10,7 @@ const dartSass = require('sass-embedded') // Local dependencies const config = require('./app/config') -const { findAvailablePort } = require('./lib/utils') +const { findAvailablePort } = require('./app/find-available-port') // Set configuration variables const port = parseInt(process.env.PORT || config.port, 10) || 2000 From c826e629a267997d72878c15b8d6413fe8069f38 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Tue, 11 Nov 2025 19:44:15 +0000 Subject: [PATCH 07/13] Remove lib folder --- lib/core_filters.js | 40 --- .../blank-transactional.html | 22 -- lib/example-templates/content-page.html | 30 -- lib/example-templates/example-templates.html | 38 --- lib/example-templates/mini-hub/index.html | 58 ---- lib/example-templates/mini-hub/page-2.html | 66 ---- lib/example-templates/mini-hub/page-3.html | 64 ---- lib/example_templates_routes.js | 6 - lib/middleware/authentication.js | 75 ----- lib/middleware/auto-routing.js | 60 ---- lib/middleware/production.js | 34 -- lib/middleware/prototype-admin-routes.js | 89 ------ lib/prototype-admin/password.html | 54 ---- lib/prototype-admin/reset-done.html | 15 - lib/prototype-admin/reset.html | 27 -- lib/template.env | 0 lib/template.session-data-defaults.js | 22 -- lib/templates/prototype-kit-template.njk | 46 --- lib/utils.js | 299 +----------------- 19 files changed, 1 insertion(+), 1044 deletions(-) delete mode 100644 lib/core_filters.js delete mode 100755 lib/example-templates/blank-transactional.html delete mode 100755 lib/example-templates/content-page.html delete mode 100644 lib/example-templates/example-templates.html delete mode 100644 lib/example-templates/mini-hub/index.html delete mode 100644 lib/example-templates/mini-hub/page-2.html delete mode 100644 lib/example-templates/mini-hub/page-3.html delete mode 100644 lib/example_templates_routes.js delete mode 100644 lib/middleware/authentication.js delete mode 100644 lib/middleware/auto-routing.js delete mode 100644 lib/middleware/production.js delete mode 100644 lib/middleware/prototype-admin-routes.js delete mode 100644 lib/prototype-admin/password.html delete mode 100644 lib/prototype-admin/reset-done.html delete mode 100644 lib/prototype-admin/reset.html delete mode 100644 lib/template.env delete mode 100644 lib/template.session-data-defaults.js delete mode 100644 lib/templates/prototype-kit-template.njk diff --git a/lib/core_filters.js b/lib/core_filters.js deleted file mode 100644 index af2e8db9..00000000 --- a/lib/core_filters.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @param {Environment} env - */ -module.exports = function (env) { - // If you need access to an internal nunjucks filter you can use env - // see the example below for 'safe' which is used in 'filters.log' - const nunjucksSafe = env.getFilter('safe') - - /** - * Object used to store the filters - * filters.foo("input") here, becomes {{ "input" | foo }} in templates - */ - const filters = {} - - /** - * Logs an object in the template to the console in the browser. - * - * @example - * ```njk - * {{ "hello world" | log }} - * ``` - * @example For environments with autoescaping turned on - * ```njk - * {{ "hello world" | log | safe }} - * ``` - * @param {unknown} a - unknown type - * @returns {string} a script tag with a console.log call. - */ - filters.log = function log(a) { - return nunjucksSafe( - `` - ) - } - - return filters -} - -/** - * @import { Environment } from 'nunjucks' - */ diff --git a/lib/example-templates/blank-transactional.html b/lib/example-templates/blank-transactional.html deleted file mode 100755 index 6626bc13..00000000 --- a/lib/example-templates/blank-transactional.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "layout.html" %} - -{% set mainClasses = "nhsuk-main-wrapper--s" %} - -{% set pageName = "Blank transactional template" %} - -{% block beforeContent %} - {{ backLink({ - href: "#", - text: "Back" - }) }} -{% endblock %} - -{% block content %} -
-
- - - -
-
-{% endblock %} diff --git a/lib/example-templates/content-page.html b/lib/example-templates/content-page.html deleted file mode 100755 index dca0a1d5..00000000 --- a/lib/example-templates/content-page.html +++ /dev/null @@ -1,30 +0,0 @@ -{% extends "layout.html" %} - -{% set pageName = "Example content page" %} - -{% block beforeContent %} - {{ breadcrumb({ - href: "#", - text: "Home" - }) }} -{% endblock %} - -{% block content %} -
- -
- -

- {{ pageName }} -

- -

- Visit the - NHS digital service manual - for guidance and code examples. -

- -
- -
-{% endblock %} diff --git a/lib/example-templates/example-templates.html b/lib/example-templates/example-templates.html deleted file mode 100644 index 368fdd2d..00000000 --- a/lib/example-templates/example-templates.html +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "layout.html" %} - -{% set pageName = "Page templates" %} - -{% block beforeContent %} - {{ breadcrumb({ - href: "/", - text: "Home" - }) }} -{% endblock %} - -{% block content %} -
- -
- -

{{ pageName }}

- -

You can find these templates in the /lib/example-templates folder.

- -

You can copy and paste the templates in any folder within /app/views.

- -

Content pages

- - - -

Transactional journeys

- - -
- -
-{% endblock %} diff --git a/lib/example-templates/mini-hub/index.html b/lib/example-templates/mini-hub/index.html deleted file mode 100644 index 4f99a339..00000000 --- a/lib/example-templates/mini-hub/index.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends "layout.html" %} - -{% set pageName = "Mini hub" %} - -{% block beforeContent %} - {{ breadcrumb({ - href: "/", - text: "Home" - }) }} -{% endblock %} - -{% block content %} -
-
- -

- Main page heading - - Section title - -

- - {{ contentsList({ - items: [ - { - href: "/example-templates/mini-hub/page-1", - text: "Main page", - current: "true" - }, - { - href: "/example-templates/mini-hub/page-2", - text: "Page two" - }, - { - href: "/example-templates/mini-hub/page-3", - text: "Page three" - } - ] - }) }} - -

- [Page content goes here] -

- -

- [Visit the - NHS digital service manual - for guidance and examples.] -

- - {{ pagination({ - nextUrl: "/example-templates/mini-hub/page-2", - nextPage: "Page two" - }) }} - -
-
-{% endblock %} diff --git a/lib/example-templates/mini-hub/page-2.html b/lib/example-templates/mini-hub/page-2.html deleted file mode 100644 index 078ac3d0..00000000 --- a/lib/example-templates/mini-hub/page-2.html +++ /dev/null @@ -1,66 +0,0 @@ -{% extends "layout.html" %} - -{% set pageName = "Mini hub - Page two" %} - -{% block beforeContent %} - {{ breadcrumb({ - items: [ - { - href: "/", - text: "Home" - } - ], - href: "/example-templates/mini-hub", - text: "Main page" - }) }} -{% endblock %} - -{% block content %} -
-
- -

- Page two heading - - Section title - -

- - {{ contentsList({ - items: [ - { - href: "/example-templates/mini-hub", - text: "Main page" - }, - { - href: "/example-templates/mini-hub/page-2", - text: "Page two", - current: "true" - }, - { - href: "/example-templates/mini-hub/page-3", - text: "Page three" - } - ] - }) }} - -

- [Page content goes here] -

- -

- [Visit the - NHS digital service manual - for guidance and examples.] -

- - {{ pagination({ - previousUrl: "/example-templates/mini-hub", - previousPage: "Main page", - nextUrl: "/example-templates/mini-hub/page-3", - nextPage: "Page two" - }) }} - -
-
-{% endblock %} diff --git a/lib/example-templates/mini-hub/page-3.html b/lib/example-templates/mini-hub/page-3.html deleted file mode 100644 index 6a9e5e69..00000000 --- a/lib/example-templates/mini-hub/page-3.html +++ /dev/null @@ -1,64 +0,0 @@ -{% extends "layout.html" %} - -{% set pageName = "Mini hub - Page three" %} - -{% block beforeContent %} - {{ breadcrumb({ - items: [ - { - href: "/", - text: "Home" - } - ], - href: "/example-templates/mini-hub", - text: "Main page" - }) }} -{% endblock %} - -{% block content %} -
-
- -

- Page three heading - - Section title - -

- - {{ contentsList({ - items: [ - { - href: "/example-templates/mini-hub", - text: "Main page" - }, - { - href: "/example-templates/mini-hub/page-2", - text: "Page two" - }, - { - href: "/example-templates/mini-hub/page-3", - text: "Page three", - current: "true" - } - ] - }) }} - -

- [Page content goes here] -

- -

- [Visit the - NHS digital service manual - for guidance and examples.] -

- - {{ pagination({ - previousUrl: "/example-templates/mini-hub/page-2", - previousPage: "Page two" - }) }} - -
-
-{% endblock %} diff --git a/lib/example_templates_routes.js b/lib/example_templates_routes.js deleted file mode 100644 index af49e842..00000000 --- a/lib/example_templates_routes.js +++ /dev/null @@ -1,6 +0,0 @@ -// External dependencies -const express = require('express') - -const router = express.Router() - -module.exports = router diff --git a/lib/middleware/authentication.js b/lib/middleware/authentication.js deleted file mode 100644 index 8e1fcc8a..00000000 --- a/lib/middleware/authentication.js +++ /dev/null @@ -1,75 +0,0 @@ -const { format: urlFormat } = require('node:url') - -const { encryptPassword } = require('../utils') - -const allowedPathsWhenUnauthenticated = [ - '/prototype-admin/password', - '/css/main.css', - '/css/main.css.map', - '/nhsuk-frontend/nhsuk-frontend.min.js', - '/nhsuk-frontend/nhsuk-frontend.min.js.map', - '/js/auto-store-data.js', - '/js/auto-store-data.js.map', - '/js/main.js', - '/js/main.js.map' -] - -const encryptedPassword = encryptPassword(process.env.PROTOTYPE_PASSWORD) - -/** - * Redirect the user to the password page, with - * the current page path set as the returnURL in a query - * string so the user can be redirected back after successfully - * entering a password - * - * @param {Request} req - * @param {Response} res - */ -function sendUserToPasswordPage(req, res) { - const returnURL = urlFormat({ - pathname: req.path, - query: req.query - }) - const passwordPageURL = urlFormat({ - pathname: '/prototype-admin/password', - query: { returnURL } - }) - res.redirect(passwordPageURL) -} - -/** - * Give the user some instructions on how to set a password - * - * @param {Response} res - */ -function showNoPasswordError(res) { - return res.send( - '

Error:

Password not set. See guidance for setting a password.

' - ) -} - -/** - * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ -function authentication(req, res, next) { - if (!process.env.PROTOTYPE_PASSWORD) { - showNoPasswordError(res) - } else if ( - req.path.startsWith('/nhsuk-frontend/assets/') || - allowedPathsWhenUnauthenticated.includes(req.path) - ) { - next() - } else if (req.cookies.authentication === encryptedPassword) { - next() - } else { - sendUserToPasswordPage(req, res) - } -} - -module.exports = authentication - -/** - * @import { NextFunction, Request, Response } from 'express' - */ diff --git a/lib/middleware/auto-routing.js b/lib/middleware/auto-routing.js deleted file mode 100644 index 73f4a0c6..00000000 --- a/lib/middleware/auto-routing.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Automatically route pages - * - * Try to match a request to a template, for example a request for /test - * would look for /app/views/test.html and /app/views/test/index.html - * - * 1. Try to render the path - * 2. if success - send the response - * 3. if error other than template not found - call next with the error - * 4. Maybe it's a folder - try to render [path]/index.html - * 5. We got template not found both times - call next to trigger the 404 page - * 6. Remove the first slash, render won't work with it - * 7. If it's blank, render the root index - * - * @param {string} path - * @param {Response} res - * @param {NextFunction} next - */ -function renderPath(path, res, next) { - res.render(path, (error, html) => { - // [1] // - if (!error) { - res.set({ 'Content-type': 'text/html; charset=utf-8' }) // [2] // - res.end(html) - return - } - if (!error.message.startsWith('template not found')) { - // [3] // - next(error) - return - } - if (!path.endsWith('/index')) { - renderPath(`${path}/index`, res, next) // [4] // - return - } - next() // [5] // - }) -} - -/** - * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ -exports.matchRoutes = function (req, res, next) { - let { path } = req - - path = path.substr(1) // [6] // - - if (path === '') { - // [7] // - path = 'index' - } - - renderPath(path, res, next) -} - -/** - * @import { NextFunction, Request, Response } from 'express' - */ diff --git a/lib/middleware/production.js b/lib/middleware/production.js deleted file mode 100644 index 56be9ea8..00000000 --- a/lib/middleware/production.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * This Express middleware function sets some - * HTTP headers which should only be set in deployed - * environments - * - * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ -function production(req, res, next) { - // Set Strict-Transport-Security header to - // ensure that browsers only use HTTPS - res.setHeader( - 'Strict-Transport-Security', - 'max-age=31536000; includeSubDomains; preload' - ) - - // Set content security policy to upgrade - // all HTTP requests to HTTPS - res.setHeader('Content-Security-Policy', 'upgrade-insecure-requests') - - // Redirect HTTP requests to HTTPS - if (req.protocol !== 'https') { - res.redirect(302, `https://${req.get('Host')}${req.url}`) - } else { - next() - } -} - -module.exports = production - -/** - * @import { NextFunction, Request, Response } from 'express' - */ diff --git a/lib/middleware/prototype-admin-routes.js b/lib/middleware/prototype-admin-routes.js deleted file mode 100644 index 3be6d414..00000000 --- a/lib/middleware/prototype-admin-routes.js +++ /dev/null @@ -1,89 +0,0 @@ -const { join, resolve } = require('node:path') - -const express = require('express') - -const router = express.Router() - -const password = process.env.PROTOTYPE_PASSWORD - -const { encryptPassword } = require('../utils') - -router.get('/password', (req, res) => { - const returnURL = req.query.returnURL || '/' - const { error } = req.query - res.render('password', { - returnURL, - error - }) -}) - -// Check authentication password -router.post('/password', (req, res) => { - const submittedPassword = req.body.password - const { returnURL } = req.body - - if (submittedPassword === password) { - // see lib/middleware/authentication.js for explanation - res.cookie('authentication', encryptPassword(password), { - maxAge: 1000 * 60 * 60 * 24 * 30, // 30 days - sameSite: 'None', // Allows GET and POST requests from other domains - httpOnly: true, - secure: true - }) - res.redirect(returnURL) - } else { - res.redirect( - `/prototype-admin/password?error=wrong-password&returnURL=${encodeURIComponent(returnURL)}` - ) - } -}) - -router.get('/reset', (req, res) => { - let { returnPage } = req.query - - // Allow local paths only - if (!returnPage?.startsWith('/')) { - returnPage = '/' - } - - res.render('reset', { - returnPage - }) -}) - -router.all('/reset-session-data', (req, res) => { - let { returnPage } = req.body ?? req.query - - // Allow local paths only - if (!returnPage?.startsWith('/')) { - returnPage = '/' - } - - console.log('Clearing session data') - - const dataDirectory = join(__dirname, '../../app/data') - const sessionDataPath = resolve(dataDirectory, 'session-data-defaults.js') - const generatedDataPath = resolve(dataDirectory, 'generated') - - // Clear the require cache for session data defaults - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete require.cache[require.resolve(sessionDataPath)] - - // Clear cache for the generated JSON files - Object.keys(require.cache).forEach((key) => { - if (key.startsWith(generatedDataPath)) { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete require.cache[key] - } - }) - - // Load fresh session defaults after clearing cache - req.session.data = require(sessionDataPath) - req.flash('success', 'Session data cleared') - - res.render('reset-done', { - returnPage - }) -}) - -module.exports = router diff --git a/lib/prototype-admin/password.html b/lib/prototype-admin/password.html deleted file mode 100644 index d20f77c0..00000000 --- a/lib/prototype-admin/password.html +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "layout.html" %} - -{% set pageName = "Enter password" %} -{% set errors = error == "wrong-password" %} - -{% block content %} - -
-
-
- - {% if error == "wrong-password" %} - {{ errorSummary({ - titleText: "There is a problem", - errorList: [ - { - text: "The password is not correct", - href: "#password" - } - ] - })}} - {% endif %} - -

- This is a prototype used for research -

- -

- It is not a real service. You should only continue if you have been invited to test this prototype. -

- - {{ input({ - classes: "nhsuk-input--width-10", - name: "password", - id: "password", - type: "password", - errorMessage: { - text: "The password is not correct" - } if error == "wrong-password", - label:{ - text: "Password" - } - }) }} - - - - {{ button({ - text: "Continue" - }) }} - -
-
-
-{% endblock %} diff --git a/lib/prototype-admin/reset-done.html b/lib/prototype-admin/reset-done.html deleted file mode 100644 index 5356f72f..00000000 --- a/lib/prototype-admin/reset-done.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "layout.html" %} - -{% set pageName = "Data reset" %} - -{% block content %} -
-
-

{{ pageName }}

- -

The session data has been reset.

- -

Return -

-
-{% endblock %} diff --git a/lib/prototype-admin/reset.html b/lib/prototype-admin/reset.html deleted file mode 100644 index c377882e..00000000 --- a/lib/prototype-admin/reset.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends 'layout.html' %} - -{% set pageName = "Reset data" %} - -{% block beforeContent %} - {{ backLink({ - text: "Back", - href: returnPage - }) }} -{% endblock %} - -{% block content %} -
-
-

{{ pageName }}

- -

This will reset all of the data entered in this session.

- -
- - {{ button({ - text: "Reset all data" - }) }} -
-
-
-{% endblock %} diff --git a/lib/template.env b/lib/template.env deleted file mode 100644 index e69de29b..00000000 diff --git a/lib/template.session-data-defaults.js b/lib/template.session-data-defaults.js deleted file mode 100644 index 401ff107..00000000 --- a/lib/template.session-data-defaults.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - -Provide default values for user session data. These are automatically added -via the `autoStoreData` middleware. Values will only be added to the -session if a value doesn't already exist. This may be useful for testing -journeys where users are returning or logging in to an existing application. - -============================================================================ - -Example usage: - -"full-name": "Sarah Philips", - -"options-chosen": [ "foo", "bar" ] - -============================================================================ - -*/ - -module.exports = { - // Insert values here -} diff --git a/lib/templates/prototype-kit-template.njk b/lib/templates/prototype-kit-template.njk deleted file mode 100644 index f009ece8..00000000 --- a/lib/templates/prototype-kit-template.njk +++ /dev/null @@ -1,46 +0,0 @@ -{% extends "template.njk" %} - -{%- from 'action-link/macro.njk' import actionLink %} -{%- from 'back-link/macro.njk' import backLink %} -{%- from 'breadcrumb/macro.njk' import breadcrumb %} -{%- from 'button/macro.njk' import button %} -{%- from 'card/macro.njk' import card %} -{%- from 'character-count/macro.njk' import characterCount %} -{%- from 'checkboxes/macro.njk' import checkboxes %} -{%- from 'contents-list/macro.njk' import contentsList %} -{%- from 'date-input/macro.njk' import dateInput %} -{%- from 'details/macro.njk' import details %} -{%- from 'do-dont-list/macro.njk' import list %} -{%- from 'error-message/macro.njk' import errorMessage %} -{%- from 'error-summary/macro.njk' import errorSummary %} -{%- from 'fieldset/macro.njk' import fieldset %} -{%- from 'footer/macro.njk' import footer %} -{%- from 'header/macro.njk' import header %} -{%- from 'hero/macro.njk' import hero %} -{%- from 'hint/macro.njk' import hint %} -{%- from 'images/macro.njk' import image %} -{%- from 'input/macro.njk' import input %} -{%- from 'inset-text/macro.njk' import insetText %} -{%- from 'label/macro.njk' import label %} -{%- from 'notification-banner/macro.njk' import notificationBanner %} -{%- from 'pagination/macro.njk' import pagination %} -{%- from 'panel/macro.njk' import panel with context %} -{%- from 'radios/macro.njk' import radios %} -{%- from 'select/macro.njk' import select %} -{%- from 'skip-link/macro.njk' import skipLink %} -{# Renamed summary list so we prefer our app one first #} -{%- from 'summary-list/macro.njk' import summaryList as nativeSummaryList %} -{%- from 'tables/macro.njk' import table %} -{%- from 'tabs/macro.njk' import tabs %} -{%- from 'tag/macro.njk' import tag %} -{%- from 'task-list/macro.njk' import taskList %} -{%- from 'textarea/macro.njk' import textarea %} -{%- from 'warning-callout/macro.njk' import warningCallout %} - -{% block pageTitle -%} - {%- if errors === true or (errors | length) %}Error: {% endif -%} - {%- if pageName %}{{ pageName }} – {% endif -%} - {{ serviceName }} – NHS -{%- endblock %} - -{% set assetPath = '/nhsuk-frontend/assets' %} diff --git a/lib/utils.js b/lib/utils.js index b78304fc..d17e8ab8 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,306 +1,9 @@ // Core dependencies -const { createHash } = require('node:crypto') -const { resolve } = require('node:path') - -const { get: getKeypath } = require('lodash') - -const customFilters = require('../app/filters') - -const coreFilters = require('./core_filters') const { findAvailablePort } = require('./utils/find-available-port') -/** - * Merge the core and custom filters into one object - * and then add the methods to Nunjucks environment - * - * @param {Environment} env - */ -function addNunjucksFilters(env) { - const filters = { - ...coreFilters(env), - ...customFilters(env) - } - - for (const [name, filter] of Object.entries(filters)) { - env.addFilter(name, filter) - - // Duplicate filter as global function - env.addGlobal(name, filter) - } -} - -/** - * Add Nunjucks function called 'checked' to populate radios and checkboxes - * This function is less useful since NHS Frontend 9.2.0 added an - * easier way to set checkbox and radio checked items, and may - * be removed in future. - * - * @param {Environment} env - */ -function addCheckedFunction(env) { - env.addGlobal('checked', function (name, value) { - // Check data exists - if (this.ctx.data === undefined) { - return '' - } - - // Use string keys or object notation to support: - // checked("field-name") - // checked("['field-name']") - // checked("['parent']['field-name']") - const matchedName = !name.match(/[.[]/g) ? `['${name}']` : name - const storedValue = getKeypath(this.ctx.data, matchedName) - - // Check the requested data exists - if (storedValue === undefined) { - return '' - } - - let checked = '' - - // If data is an array, check it exists in the array - if (Array.isArray(storedValue)) { - if (storedValue.indexOf(value) !== -1) { - checked = 'checked' - } - } else if (storedValue === value) { - // The data is just a simple value, check it matches - checked = 'checked' - } - return checked - }) -} - -/* -// Synchronously get the URL for the latest release on GitHub and cache it -function getLatestRelease () { - if (releaseUrl !== null) { - // Release URL already exists - console.log('Release url cached:', releaseUrl) - return releaseUrl - } else { - // Release URL doesn't exist - try { - console.log('Getting latest release from GitHub') - - var res = request( - 'GET', - 'https://api.github.com/repos/alphagov/govuk-prototype-kit/releases/latest', - { - headers: { 'user-agent': 'node.js' } - } - ) - var data = JSON.parse(res.getBody('utf8')) - - // Cache releaseUrl before we return it - releaseUrl = `https://github.com/alphagov/govuk-prototype-kit/archive/${data['name']}.zip` - - console.log('Release URL is', releaseUrl) - return releaseUrl - } catch (err) { - console.log("Couldn't retrieve release URL") - return 'https://github.com/alphagov/govuk-prototype-kit/releases/latest' - } - } -} -*/ - -/** - * Try to match a request to a template, for example a request for /test - * would look for /app/views/test.html - * and /app/views/test/index.html - * - * @param {string} routePath - * @param {Response} res - * @param {NextFunction} next - */ -function renderPath(routePath, res, next) { - // Try to render the path - res.render(routePath, (error, html) => { - if (!error) { - // Success - send the response - res.set({ 'Content-type': 'text/html; charset=utf-8' }) - res.end(html) - return - } - if (!error.message.startsWith('template not found')) { - // We got an error other than template not found - call next with the error - next(error) - return - } - if (!routePath.endsWith('/index')) { - // Maybe it's a folder - try to render [path]/index.html - renderPath(`${routePath}/index`, res, next) - return - } - // We got template not found both times - call next to trigger the 404 page - next() - }) -} - -/** - * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ -function matchRoutes(req, res, next) { - let routePath = req.path - - // Remove the first slash, render won't work with it - routePath = routePath.substr(1) - - // If it's blank, render the root index - if (routePath === '') { - routePath = 'index' - } - - renderPath(routePath, res, next) -} - -/** - * Store data from POST body or GET query in session - * - * @param {{ [key: string]: unknown }} input - * @param {unknown} data - */ -function storeData(input, data) { - for (const i in input) { - // any input where the name starts with _ is ignored - if (i.indexOf('_') === 0) { - continue - } - - let val = input[i] - - // Delete values when users unselect checkboxes - if (val === '_unchecked') { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete data[i] - continue - } - - // Remove _unchecked from arrays of checkboxes - if (Array.isArray(val)) { - val = val.filter((item) => item !== '_unchecked') - } else if (typeof val === 'object') { - // Store nested objects that aren't arrays - if (typeof data[i] !== 'object') { - data[i] = {} - } - - // Add nested values - storeData(val, data[i]) - continue - } - - data[i] = val - } -} - -// Get session default data from file -let sessionDataDefaults = {} - -const sessionDataDefaultsFile = resolve( - __dirname, - '../app/data/session-data-defaults.js' -) - -try { - sessionDataDefaults = require(sessionDataDefaultsFile) -} catch (error) { - console.error( - 'Could not load the session data defaults from app/data/session-data-defaults.js. Might be a syntax error?' - ) - console.error(error) -} - -/** - * Middleware - store any data sent in session, and pass it to all views - * - * @param {Request['body']} req - * @param {Response} res - * @param {NextFunction} next - */ -function autoStoreData(req, res, next) { - if (!req.session.data) { - req.session.data = {} - } - - req.session.data = Object.assign({}, sessionDataDefaults, req.session.data) - - storeData(req.body, req.session.data) - storeData(req.query, req.session.data) - - // Send session data to all views - - res.locals.data = {} - - for (const j in req.session.data) { - res.locals.data[j] = req.session.data[j] - } - - next() -} - -/** - * Set any useful local variables - * - * @param {Request} req - * @param {Response} res - * @param {NextFunction} next - */ -function setLocals(req, res, next) { - // Current page used for the Reset data feature - res.locals.currentPage = req.originalUrl - - next() -} - -/* -function handleCookies (app) { - return function handleCookies (req, res, next) { - const COOKIE_NAME = 'seen_cookie_message' - let cookie = req.cookies[COOKIE_NAME] - - if (cookie === 'yes') { - app.locals.shouldShowCookieMessage = false - return next() - } - - let maxAgeInDays = 28 - res.cookie(COOKIE_NAME, 'yes', { - maxAge: maxAgeInDays * 24 * 60 * 60 * 1000, - httpOnly: true - }) - - app.locals.shouldShowCookieMessage = true - - next() - } -} -*/ - -/** - * @param {string} password - */ -function encryptPassword(password) { - if (!password) { - return undefined - } - const hash = createHash('sha256') - hash.update(password) - return hash.digest('hex') -} module.exports = { - addCheckedFunction, - addNunjucksFilters, - autoStoreData, - encryptPassword, - findAvailablePort, - matchRoutes, - setLocals, - storeData + findAvailablePort } /** From adc6970dea5418e5605c68e2bd509a5aeb863584 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Tue, 11 Nov 2025 19:44:37 +0000 Subject: [PATCH 08/13] Remove lib/utils --- lib/utils.js | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 lib/utils.js diff --git a/lib/utils.js b/lib/utils.js deleted file mode 100644 index d17e8ab8..00000000 --- a/lib/utils.js +++ /dev/null @@ -1,12 +0,0 @@ -// Core dependencies -const { findAvailablePort } = require('./utils/find-available-port') - - -module.exports = { - findAvailablePort -} - -/** - * @import { NextFunction, Request, Response } from 'express' - * @import { Environment } from 'nunjucks' - */ From dc002abb81e2d6a6fd4402a3e38d682724aa6da5 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Sun, 30 Nov 2025 20:25:52 +0000 Subject: [PATCH 09/13] Update to internal.4 --- package-lock.json | 759 +++++++++++++++++++++++++++++++++++++++------- package.json | 2 +- 2 files changed, 653 insertions(+), 108 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3becc923..0ad50b71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "gulp-rename": "^2.1.0", "gulp-sass": "^6.0.1", "nhsuk-frontend": "^10.0.0", - "nhsuk-prototype-kit": "8.0.0-internal.0", + "nhsuk-prototype-kit": "8.0.0-internal.4", "nunjucks": "^3.2.4", "plugin-error": "^2.0.1", "pluralize": "^8.0.0", @@ -95,6 +95,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -1789,6 +1790,422 @@ "node": ">=20.11.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", + "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz", + "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz", + "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz", + "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz", + "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz", + "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz", + "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz", + "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz", + "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz", + "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz", + "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz", + "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz", + "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz", + "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz", + "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz", + "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz", + "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz", + "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz", + "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz", + "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz", + "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz", + "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz", + "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz", + "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz", + "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz", + "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", @@ -1985,17 +2402,26 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@inquirer/checkbox": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.2.tgz", - "integrity": "sha512-E+KExNurKcUJJdxmjglTl141EwxWyAHplvsYJQgSwXf8qiNWkTxTuCCqmhFEmbIXd4zLaGMfQFJ6WrZ7fSeV3g==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2010,13 +2436,13 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.16", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.16.tgz", - "integrity": "sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==", + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2031,19 +2457,19 @@ } }, "node_modules/@inquirer/core": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", - "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2058,14 +2484,14 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.18", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.18.tgz", - "integrity": "sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==", + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/external-editor": "^1.0.1", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2080,14 +2506,14 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.18.tgz", - "integrity": "sha512-xUjteYtavH7HwDMzq4Cn2X4Qsh5NozoDHCJTdoXg9HfZ4w3R6mxV1B9tL7DGJX2eq/zqtsFjhm0/RJIMGlh3ag==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2102,13 +2528,13 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", - "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "license": "MIT", "dependencies": { - "chardet": "^2.1.0", - "iconv-lite": "^0.6.3" + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" }, "engines": { "node": ">=18" @@ -2122,23 +2548,39 @@ } } }, + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/@inquirer/figures": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", - "integrity": "sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@inquirer/input": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.2.tgz", - "integrity": "sha512-hqOvBZj/MhQCpHUuD3MVq18SSoDNHy7wEnQ8mtvs71K8OPZVXJinOzcvQna33dNYLYE4LkA9BlhAhK6MJcsVbw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2153,13 +2595,13 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.18", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.18.tgz", - "integrity": "sha512-7exgBm52WXZRczsydCVftozFTrrwbG5ySE0GqUd2zLNSBXyIucs2Wnm7ZKLe/aUu6NUg9dg7Q80QIHCdZJiY4A==", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2174,14 +2616,14 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.18.tgz", - "integrity": "sha512-zXvzAGxPQTNk/SbT3carAD4Iqi6A2JS2qtcqQjsL22uvD+JfQzUrDEtPjLL7PLn8zlSNyPdY02IiQjzoL9TStA==", + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -2196,21 +2638,21 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.4.tgz", - "integrity": "sha512-MuxVZ1en1g5oGamXV3DWP89GEkdD54alcfhHd7InUW5BifAdKQEK9SLFa/5hlWbvuhMPlobF0WAx7Okq988Jxg==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.2.2", - "@inquirer/confirm": "^5.1.16", - "@inquirer/editor": "^4.2.18", - "@inquirer/expand": "^4.0.18", - "@inquirer/input": "^4.2.2", - "@inquirer/number": "^3.0.18", - "@inquirer/password": "^4.0.18", - "@inquirer/rawlist": "^4.1.6", - "@inquirer/search": "^3.1.1", - "@inquirer/select": "^4.3.2" + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" }, "engines": { "node": ">=18" @@ -2225,14 +2667,14 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.6.tgz", - "integrity": "sha512-KOZqa3QNr3f0pMnufzL7K+nweFFCCBs6LCXZzXDrVGTyssjLeudn5ySktZYv1XiSqobyHRYYK0c6QsOxJEhXKA==", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2247,15 +2689,15 @@ } }, "node_modules/@inquirer/search": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.1.tgz", - "integrity": "sha512-TkMUY+A2p2EYVY3GCTItYGvqT6LiLzHBnqsU1rJbrpXUijFfM6zvUx0R4civofVwFCmJZcKqOVwwWAjplKkhxA==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2270,16 +2712,16 @@ } }, "node_modules/@inquirer/select": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.2.tgz", - "integrity": "sha512-nwous24r31M+WyDEHV+qckXkepvihxhnyIaod2MG7eCE6G0Zm/HUF6jgN8GXgf4U7AU6SLseKdanY195cwvU6w==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.2.0", - "@inquirer/figures": "^1.0.13", - "@inquirer/type": "^3.0.8", - "ansi-escapes": "^4.3.2", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -2294,9 +2736,9 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.8.tgz", - "integrity": "sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==", + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "license": "MIT", "engines": { "node": ">=18" @@ -3390,6 +3832,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -3463,6 +3914,7 @@ "integrity": "sha512-8fz6oa6wEKZrhXWro/S3n2eRJqlRcIa6SlDh59FXJ5Wp5XRZ8B9ixpJDcjadHq47hMx0u+HW6SNa6LjJQ6NLtw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.41.0", @@ -3493,6 +3945,7 @@ "integrity": "sha512-gTtSdWX9xiMPA/7MV9STjJOOYtWwIJIYxkQxnSV1U3xcE+mnJSH3f6zI0RYP+ew66WSlZ5ed+h0VCxsvdC1jJg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.41.0", "@typescript-eslint/types": "8.41.0", @@ -4006,6 +4459,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4068,6 +4522,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -5037,6 +5492,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001735", "electron-to-chromium": "^1.5.204", @@ -5293,9 +5749,9 @@ } }, "node_modules/chardet": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", - "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", "license": "MIT" }, "node_modules/chokidar": { @@ -6497,6 +6953,63 @@ "es6-symbol": "^3.1.1" } }, + "node_modules/esbuild": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", + "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==", + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.0", + "@esbuild/android-arm": "0.27.0", + "@esbuild/android-arm64": "0.27.0", + "@esbuild/android-x64": "0.27.0", + "@esbuild/darwin-arm64": "0.27.0", + "@esbuild/darwin-x64": "0.27.0", + "@esbuild/freebsd-arm64": "0.27.0", + "@esbuild/freebsd-x64": "0.27.0", + "@esbuild/linux-arm": "0.27.0", + "@esbuild/linux-arm64": "0.27.0", + "@esbuild/linux-ia32": "0.27.0", + "@esbuild/linux-loong64": "0.27.0", + "@esbuild/linux-mips64el": "0.27.0", + "@esbuild/linux-ppc64": "0.27.0", + "@esbuild/linux-riscv64": "0.27.0", + "@esbuild/linux-s390x": "0.27.0", + "@esbuild/linux-x64": "0.27.0", + "@esbuild/netbsd-arm64": "0.27.0", + "@esbuild/netbsd-x64": "0.27.0", + "@esbuild/openbsd-arm64": "0.27.0", + "@esbuild/openbsd-x64": "0.27.0", + "@esbuild/openharmony-arm64": "0.27.0", + "@esbuild/sunos-x64": "0.27.0", + "@esbuild/win32-arm64": "0.27.0", + "@esbuild/win32-ia32": "0.27.0", + "@esbuild/win32-x64": "0.27.0" + } + }, + "node_modules/esbuild-sass-plugin": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-3.3.1.tgz", + "integrity": "sha512-SnO1ls+d52n6j8gRRpjexXI8MsHEaumS0IdDHaYM29Y6gakzZYMls6i9ql9+AWMSQk/eryndmUpXEgT34QrX1A==", + "license": "MIT", + "dependencies": { + "resolve": "^1.22.8", + "safe-identifier": "^0.4.2", + "sass": "^1.71.1" + }, + "peerDependencies": { + "esbuild": ">=0.20.1", + "sass-embedded": "^1.71.1" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -6532,6 +7045,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -6735,6 +7249,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -6936,6 +7451,7 @@ "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "builtins": "^5.0.1", @@ -7012,6 +7528,7 @@ "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", "dev": true, "license": "ISC", + "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -9959,6 +10476,23 @@ "node": ">=8.0.0" } }, + "node_modules/http-proxy-middleware": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.5.tgz", + "integrity": "sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==", + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.15", + "debug": "^4.3.6", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.3", + "is-plain-object": "^5.0.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -10904,6 +11438,7 @@ "integrity": "sha512-yC3JvpP/ZcAZX5rYCtXO/g9k6VTCQz0VFE2v1FpxytWzUqfDtu0XL/pwnNvptzYItvGwomh1ehomRNMOyhCJKw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "30.1.1", "@jest/types": "30.0.5", @@ -12405,23 +12940,30 @@ "resolved": "https://registry.npmjs.org/nhsuk-frontend/-/nhsuk-frontend-10.0.0.tgz", "integrity": "sha512-WrvUfYi+FAqcDjQIvtvhx4V6+5nL/K7PvFXp/IwuAQl6F9q+RwxStsr4BBufhSVSfp9vYs7ldegLsO0UtzdJAQ==", "license": "MIT", + "peer": true, "engines": { "node": "^20.9.0 || ^22.11.0" } }, "node_modules/nhsuk-prototype-kit": { - "version": "8.0.0-internal.0", - "resolved": "https://registry.npmjs.org/nhsuk-prototype-kit/-/nhsuk-prototype-kit-8.0.0-internal.0.tgz", - "integrity": "sha512-YmHdPnL1d8LiDD2SORVVMZpkwqPFfvelapTMjX9f+66IXDQZ/tyBSbIaPmJlhYg+8HnVnRzJEgJGCUGk88samg==", + "version": "8.0.0-internal.4", + "resolved": "https://registry.npmjs.org/nhsuk-prototype-kit/-/nhsuk-prototype-kit-8.0.0-internal.4.tgz", + "integrity": "sha512-vQgkuOyvzhLyizcfFHsO/9s8a+FHHjz0ljM2Xj6yqwcdB88KvEoZV5njmhCD8CVIzbsv8WA7LElEaz/RPqlv3w==", "license": "MIT", "workspaces": [ ".", "testapp" ], "dependencies": { + "@inquirer/prompts": "^7.9.0", "body-parser": "^2.2.0", + "browser-sync": "^3.0.4", "cookie-parser": "^1.4.7", - "express-session": "^1.18.1" + "esbuild": "^0.27.0", + "esbuild-sass-plugin": "^3.3.1", + "express-session": "^1.18.1", + "http-proxy-middleware": "^3.0.5", + "portscanner": "^2.2.0" }, "engines": { "node": "^20.13.0 || ^22.11.0 || ^24.11.0" @@ -14252,6 +14794,12 @@ ], "license": "MIT" }, + "node_modules/safe-identifier": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/safe-identifier/-/safe-identifier-0.4.2.tgz", + "integrity": "sha512-6pNbSMW6OhAi9j+N8V+U715yBQsaWJ7eyEUaOrawX+isg5ZxhUlV1NipNtgaKHmFGiABwt+ZF04Ii+3Xjkg+8w==", + "license": "ISC" + }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -14307,7 +14855,6 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.91.0.tgz", "integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==", "license": "MIT", - "optional": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -14328,6 +14875,7 @@ "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.91.0.tgz", "integrity": "sha512-VTckYcH1AglrZ3VpPETilTo3Ef472XKwP13lrNfbOHSR6Eo5p27XTkIi+6lrCbuhBFFGAmy+4BRoLaeFUgn+eg==", "license": "MIT", + "peer": true, "dependencies": { "@bufbuild/protobuf": "^2.5.0", "buffer-builder": "^0.2.0", @@ -14679,7 +15227,6 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "license": "MIT", - "optional": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -14694,15 +15241,13 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/sass/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==", "license": "MIT", - "optional": true, "engines": { "node": ">= 14.18.0" }, @@ -15600,7 +16145,6 @@ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", - "optional": true, "engines": { "node": ">=0.10.0" } @@ -16419,6 +16963,7 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" diff --git a/package.json b/package.json index d8a663f5..7df0e60f 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "gulp-rename": "^2.1.0", "gulp-sass": "^6.0.1", "nhsuk-frontend": "^10.0.0", - "nhsuk-prototype-kit": "8.0.0-internal.0", + "nhsuk-prototype-kit": "8.0.0-internal.4", "nunjucks": "^3.2.4", "plugin-error": "^2.0.1", "pluralize": "^8.0.0", From f7b18d555ad07efb06078b351178028d3d1b85ff Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Sun, 30 Nov 2025 20:26:49 +0000 Subject: [PATCH 10/13] Use prototype.start() --- app.js | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/app.js b/app.js index e248a3f2..53da8ead 100755 --- a/app.js +++ b/app.js @@ -68,7 +68,7 @@ for (const [name, filter] of Object.entries(filters())) { nunjucksAppEnv.addGlobal(name, filter) } -NHSPrototypeKit.init({ +const prototype = NHSPrototypeKit.init({ serviceName: config.serviceName, express: app, nunjucks: nunjucksAppEnv, @@ -77,23 +77,4 @@ NHSPrototypeKit.init({ sessionDataDefaults: sessionDataDefaults }) -// Run the application -app.listen(port) - -if ( - process.env.WATCH !== 'true' && // If the user isn’t running watch - process.env.NODE_ENV !== 'production' // and it’s not in production mode -) { - console.info(`Running at http://localhost:${port}/`) - console.info('') - console.warn( - 'Warning: It looks like you may have run the command `npm start` locally.' - ) - console.warn('Press `Ctrl+C` and then run `npm run watch` instead') -} - -module.exports = app - -/** - * @import { ConfigureOptions } from 'nunjucks' - */ +prototype.start() From 6da959269bf15cb74d73f596ed4bc2023ce1dd01 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Sun, 30 Nov 2025 20:27:52 +0000 Subject: [PATCH 11/13] Remove unused files --- app/find-available-port.js | 39 --------- gulpfile.js | 163 ------------------------------------- 2 files changed, 202 deletions(-) delete mode 100644 app/find-available-port.js delete mode 100755 gulpfile.js diff --git a/app/find-available-port.js b/app/find-available-port.js deleted file mode 100644 index af75d16c..00000000 --- a/app/find-available-port.js +++ /dev/null @@ -1,39 +0,0 @@ -const inquirer = require('@inquirer/prompts') -const { checkPortStatus, findAPortNotInUse } = require('portscanner') - -/** - * Find an available port to run a server on. This will check - * whether the default port is available and if not, will ask - * the user whether to switch to an available port. - * - * @param {number} [startPort] - Find port starting from this port number (optional) - */ -async function findAvailablePort(startPort = 3000) { - const host = '127.0.0.1' - - // Check default port is free - if ((await checkPortStatus(startPort, host)) === 'closed') { - return startPort - } - - console.error( - `ERROR: Port ${startPort} in use - you may have another prototype running.\n` - ) - - const change = inquirer.confirm({ - message: 'Change to an available port?', - default: false - }) - - // Check whether the default port or the default port + 1000 - // is free. (1000 is added because that’s what we use for BrowserSync) - if (await change.catch(() => false)) { - return findAPortNotInUse(startPort, startPort + 1000, host) - } - - return undefined -} - -module.exports = { - findAvailablePort -} diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100755 index 17a513a4..00000000 --- a/gulpfile.js +++ /dev/null @@ -1,163 +0,0 @@ -// External dependencies -const browserSync = require('browser-sync') -const gulp = require('gulp') -const babel = require('gulp-babel') -const clean = require('gulp-clean') -const nodemon = require('gulp-nodemon') -const gulpSass = require('gulp-sass') -const PluginError = require('plugin-error') -const dartSass = require('sass-embedded') - -// Local dependencies -const config = require('./app/config') -const { findAvailablePort } = require('./app/find-available-port') - -// Set configuration variables -const port = parseInt(process.env.PORT || config.port, 10) || 2000 - -// Delete all the files in /public build directory -function cleanPublic() { - return gulp.src('public', { allowEmpty: true }).pipe(clean()) -} - -// Set Sass compiler -const sass = gulpSass(dartSass) - -// Compile SASS to CSS -function compileStyles() { - return gulp - .src(['app/assets/sass/**/*.scss'], { - sourcemaps: true - }) - .pipe( - sass({ - loadPaths: ['node_modules'], - sourceMap: true, - sourceMapIncludeSources: true - }).on('error', (error) => { - throw new PluginError('compileCSS', error.messageFormatted, { - showProperties: false - }) - }) - ) - .pipe( - gulp.dest('public/css', { - sourcemaps: '.' - }) - ) -} - -// Compile JavaScript (with ES6 support) -function compileScripts() { - return gulp - .src(['app/assets/javascript/**/*.js'], { - sourcemaps: true - }) - .pipe(babel()) - .pipe( - gulp.dest('public/js', { - sourcemaps: '.' - }) - ) -} - -// Compile assets -function compileAssets() { - return gulp - .src( - [ - 'app/assets/**/**/*.*', - '!**/assets/**/**/*.js', // Don't copy JS files - '!**/assets/**/**/*.scss' // Don't copy SCSS files - ], - { encoding: false } - ) - .pipe(gulp.dest('public')) -} - -// Start nodemon -async function startNodemon(done) { - let availablePort - - try { - availablePort = await findAvailablePort(port) - if (!availablePort) { - throw new Error(`Port ${port} in use`) - } - } catch (error) { - done(new PluginError('startNodemon', error)) - return - } - - process.env.PORT = availablePort - process.env.WATCH = 'true' - - const server = nodemon({ - script: 'app.js', - stdout: true, - ext: 'js json', - watch: ['.env', 'app.js', 'app', 'lib'], - ignore: ['app/assets', 'app/data/generated', '**.test.*'], - quiet: false - }) - - let starting = false - - const onReady = () => { - starting = false - done() - } - - server.on('start', () => { - starting = true - setTimeout(onReady) - }) - - server.on('stdout', (stdout) => { - process.stdout.write(stdout) - if (starting) { - onReady() - } - }) -} - -// Start browsersync -async function startBrowserSync(done) { - const proxyPort = parseInt(process.env.PORT, 10) - - browserSync.init( - { - proxy: `localhost:${proxyPort}`, - port: proxyPort + 1000, - ui: false, - files: ['app/views/**/*.*', 'lib/example-templates/**/*.*'], - ghostMode: false, - open: false, - notify: false, - logFileChanges: false, - reloadDebounce: 1000 - }, - done - ) - - gulp.watch('public/**/*.*').on('change', browserSync.reload) -} - -// Watch for changes within assets/ -function watch() { - gulp.watch('app/assets/sass/**/*.scss', compileStyles) - gulp.watch('app/assets/javascript/**/*.js', compileScripts) - gulp.watch('app/assets/**/**/*.*', compileAssets) -} - -exports.watch = watch -exports.compileStyles = compileStyles -exports.compileScripts = compileScripts -exports.cleanPublic = cleanPublic - -gulp.task( - 'build', - gulp.series(cleanPublic, compileStyles, compileScripts, compileAssets) -) - -gulp.task('default', gulp.series(startNodemon, startBrowserSync, watch)) From 2c931107e0b0e0de50a5b233f564b92b1a45adf5 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Sun, 30 Nov 2025 20:28:39 +0000 Subject: [PATCH 12/13] Remove unused dependencies --- package-lock.json | 131 +--------------------------------------------- package.json | 8 --- 2 files changed, 2 insertions(+), 137 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0ad50b71..ea72213f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,14 +7,11 @@ "": { "name": "nhsuk-prototype-kit", "version": "5.0.0", - "hasInstallScript": true, "license": "MIT", "dependencies": { "@babel/core": "^7.28.3", "@babel/preset-env": "^7.28.3", "@faker-js/faker": "^10.0.0", - "@inquirer/prompts": "^7.8.4", - "browser-sync": "^3.0.4", "connect-flash": "^0.1.1", "dayjs": "^1.11.15", "express": "^5.1.0", @@ -30,9 +27,7 @@ "nunjucks": "^3.2.4", "plugin-error": "^2.0.1", "pluralize": "^8.0.0", - "portscanner": "^2.2.0", "sass-embedded": "^1.91.0", - "session-file-store": "^1.5.0", "weighted": "^1.0.0" }, "devDependencies": { @@ -3880,6 +3875,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz", "integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==", "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.10.0" } @@ -4911,18 +4907,6 @@ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "license": "MIT" }, - "node_modules/asn1.js": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", - "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.0.0", - "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", @@ -5183,12 +5167,6 @@ "node": ">=10.13.0" } }, - "node_modules/bagpipe": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/bagpipe/-/bagpipe-0.3.5.tgz", - "integrity": "sha512-42sAlmPDKes1nLm/aly+0VdaopSU9br+jkRELedhQxI5uXHgtk47I83Mpmf4zoNTRMASdLFtUkimlu/Z9zQ8+g==", - "license": "MIT" - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -5327,12 +5305,6 @@ "node": ">= 6" } }, - "node_modules/bn.js": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", - "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", - "license": "MIT" - }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -10601,6 +10573,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -11213,12 +11186,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "license": "MIT" - }, "node_modules/is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", @@ -12153,18 +12120,6 @@ "node": ">=0.10.0" } }, - "node_modules/kruptein": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-2.2.3.tgz", - "integrity": "sha512-BTwprBPTzkFT9oTugxKd3WnWrX630MqUDsnmBuoa98eQs12oD4n4TeI0GbpdGcYn/73Xueg2rfnw+oK4dovnJg==", - "license": "MIT", - "dependencies": { - "asn1.js": "^5.4.1" - }, - "engines": { - "node": ">6" - } - }, "node_modules/last-run": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz", @@ -12748,12 +12703,6 @@ "node": ">=6" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "license": "ISC" - }, "node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", @@ -14608,15 +14557,6 @@ "node": ">=0.12" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -15533,64 +15473,6 @@ "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", "license": "ISC" }, - "node_modules/session-file-store": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/session-file-store/-/session-file-store-1.5.0.tgz", - "integrity": "sha512-60IZaJNzyu2tIeHutkYE8RiXVx3KRvacOxfLr2Mj92SIsRIroDsH0IlUUR6fJAjoTW4RQISbaOApa2IZpIwFdQ==", - "license": "Apache-2.0", - "dependencies": { - "bagpipe": "^0.3.5", - "fs-extra": "^8.0.1", - "kruptein": "^2.0.4", - "object-assign": "^4.1.1", - "retry": "^0.12.0", - "write-file-atomic": "3.0.3" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/session-file-store/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/session-file-store/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/session-file-store/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/session-file-store/node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -17070,15 +16952,6 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "license": "MIT", - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/typescript": { "version": "5.9.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", diff --git a/package.json b/package.json index 7df0e60f..8180034e 100644 --- a/package.json +++ b/package.json @@ -4,12 +4,8 @@ "description": "Rapidly create HTML prototypes of NHS websites and services.", "main": "app.js", "scripts": { - "build": "gulp build", - "postinstall": "npm run build", "start": "node app.js", "test": "jest --coverage=true", - "prewatch": "gulp build", - "watch": "gulp", "lint": "npm run lint:js && npm run lint:prettier", "lint:fix": "npm run lint:js:fix && npm run lint:prettier:fix", "lint:prettier": "prettier --cache --cache-location .cache/prettier --cache-strategy content --check .", @@ -23,8 +19,6 @@ "@babel/core": "^7.28.3", "@babel/preset-env": "^7.28.3", "@faker-js/faker": "^10.0.0", - "@inquirer/prompts": "^7.8.4", - "browser-sync": "^3.0.4", "connect-flash": "^0.1.1", "dayjs": "^1.11.15", "express": "^5.1.0", @@ -40,9 +34,7 @@ "nunjucks": "^3.2.4", "plugin-error": "^2.0.1", "pluralize": "^8.0.0", - "portscanner": "^2.2.0", "sass-embedded": "^1.91.0", - "session-file-store": "^1.5.0", "weighted": "^1.0.0" }, "devDependencies": { From 7c966bd6e0c17238a9b4309d6679da30ffade141 Mon Sep 17 00:00:00 2001 From: Frankie Roberto Date: Sun, 30 Nov 2025 20:36:14 +0000 Subject: [PATCH 13/13] Fix CSS reference --- app.js | 8 +++++++- app/views/_templates/layout.html | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app.js b/app.js index 53da8ead..fa5d483f 100755 --- a/app.js +++ b/app.js @@ -51,6 +51,9 @@ let nunjucksAppEnv = nunjucks.configure(appViews, nunjucksConfig) // Flash messages app.use(flash()) +// Serve the images as static assets +app.use('/images', express.static(join(__dirname, 'app/assets/images'))) + // Use public folder for static assets app.use(express.static(join(__dirname, 'public'))) @@ -74,7 +77,10 @@ const prototype = NHSPrototypeKit.init({ nunjucks: nunjucksAppEnv, routes: routes, locals: locals, - sessionDataDefaults: sessionDataDefaults + sessionDataDefaults: sessionDataDefaults, + buildOptions: { + entryPoints: ['app/assets/sass/main.scss', 'app/assets/javascript/**/*.js'] + } }) prototype.start() diff --git a/app/views/_templates/layout.html b/app/views/_templates/layout.html index 264306bc..7c7f58a7 100755 --- a/app/views/_templates/layout.html +++ b/app/views/_templates/layout.html @@ -24,7 +24,7 @@ {% block head %} - + {% endblock %}