@dwp/govuk-casa 7.0.7 → 7.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -0
- package/dist/assets/css/casa-ie8.css +1 -0
- package/dist/assets/css/casa.css +1 -0
- package/dist/casa/css/casa-ie8.css +1 -1
- package/dist/casa/css/casa.css +1 -1
- package/dist/casa.d.ts +11 -0
- package/dist/casa.js +46 -0
- package/dist/lib/CasaTemplateLoader.d.ts +29 -0
- package/dist/lib/CasaTemplateLoader.js +74 -0
- package/dist/lib/JourneyContext.d.ts +297 -0
- package/dist/lib/JourneyContext.js +581 -0
- package/dist/lib/MutableRouter.d.ts +155 -0
- package/dist/lib/MutableRouter.js +277 -0
- package/dist/lib/Plan.d.ts +154 -0
- package/dist/lib/Plan.js +442 -0
- package/dist/lib/ValidationError.d.ts +74 -0
- package/dist/lib/ValidationError.js +159 -0
- package/dist/lib/ValidatorFactory.d.ts +83 -0
- package/dist/lib/ValidatorFactory.js +106 -0
- package/dist/lib/configuration-ingestor.d.ts +262 -0
- package/dist/lib/configuration-ingestor.js +490 -0
- package/dist/lib/configure.d.ts +90 -0
- package/dist/lib/configure.js +192 -0
- package/dist/lib/dirname.cjs +1 -0
- package/dist/lib/dirname.d.cts +2 -0
- package/dist/lib/end-session.d.ts +13 -0
- package/dist/lib/end-session.js +43 -0
- package/dist/lib/field.d.ts +77 -0
- package/dist/lib/field.js +255 -0
- package/dist/lib/index.d.ts +14 -0
- package/dist/lib/index.js +54 -0
- package/dist/lib/logger.d.ts +9 -0
- package/dist/lib/logger.js +18 -0
- package/dist/lib/nunjucks-filters.d.ts +26 -0
- package/dist/lib/nunjucks-filters.js +90 -0
- package/dist/lib/nunjucks.d.ts +23 -0
- package/dist/lib/nunjucks.js +49 -0
- package/dist/lib/utils.d.ts +48 -0
- package/dist/lib/utils.js +111 -0
- package/dist/lib/validators/dateObject.d.ts +4 -0
- package/dist/lib/validators/dateObject.js +135 -0
- package/dist/lib/validators/email.d.ts +4 -0
- package/dist/lib/validators/email.js +46 -0
- package/dist/lib/validators/inArray.d.ts +4 -0
- package/dist/lib/validators/inArray.js +60 -0
- package/dist/lib/validators/index.d.ts +21 -0
- package/dist/lib/validators/index.js +47 -0
- package/dist/lib/validators/nino.d.ts +4 -0
- package/dist/lib/validators/nino.js +46 -0
- package/dist/lib/validators/postalAddressObject.d.ts +4 -0
- package/dist/lib/validators/postalAddressObject.js +123 -0
- package/dist/lib/validators/regex.d.ts +4 -0
- package/dist/lib/validators/regex.js +40 -0
- package/dist/lib/validators/required.d.ts +4 -0
- package/dist/lib/validators/required.js +56 -0
- package/dist/lib/validators/strlen.d.ts +4 -0
- package/dist/lib/validators/strlen.js +51 -0
- package/dist/lib/validators/wordCount.d.ts +5 -0
- package/dist/lib/validators/wordCount.js +54 -0
- package/dist/lib/waypoint-url.d.ts +23 -0
- package/dist/lib/waypoint-url.js +52 -0
- package/dist/middleware/body-parser.d.ts +1 -0
- package/dist/middleware/body-parser.js +24 -0
- package/dist/middleware/csrf.d.ts +1 -0
- package/dist/middleware/csrf.js +31 -0
- package/dist/middleware/data.d.ts +5 -0
- package/dist/middleware/data.js +53 -0
- package/dist/middleware/dirname.cjs +1 -0
- package/dist/middleware/dirname.d.cts +2 -0
- package/dist/middleware/gather-fields.d.ts +6 -0
- package/dist/middleware/gather-fields.js +48 -0
- package/dist/middleware/i18n.d.ts +4 -0
- package/dist/middleware/i18n.js +88 -0
- package/dist/middleware/post.d.ts +3 -0
- package/dist/middleware/post.js +57 -0
- package/dist/middleware/pre.d.ts +3 -0
- package/dist/middleware/pre.js +51 -0
- package/dist/middleware/progress-journey.d.ts +6 -0
- package/dist/middleware/progress-journey.js +80 -0
- package/dist/middleware/sanitise-fields.d.ts +5 -0
- package/dist/middleware/sanitise-fields.js +53 -0
- package/dist/middleware/session.d.ts +11 -0
- package/dist/middleware/session.js +121 -0
- package/dist/middleware/skip-waypoint.d.ts +5 -0
- package/dist/middleware/skip-waypoint.js +43 -0
- package/dist/middleware/steer-journey.d.ts +7 -0
- package/dist/middleware/steer-journey.js +62 -0
- package/dist/middleware/validate-fields.d.ts +7 -0
- package/dist/middleware/validate-fields.js +67 -0
- package/dist/mjs/esm-wrapper.js +11 -0
- package/dist/mjs/package.json +3 -0
- package/dist/package.json +3 -0
- package/dist/routes/ancillary.d.ts +11 -0
- package/dist/routes/ancillary.js +27 -0
- package/dist/routes/dirname.cjs +1 -0
- package/dist/routes/dirname.d.cts +2 -0
- package/dist/routes/journey.d.ts +8 -0
- package/dist/routes/journey.js +127 -0
- package/dist/routes/static.d.ts +26 -0
- package/dist/routes/static.js +68 -0
- package/package.json +19 -19
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.validateEvents = exports.validatePlugins = exports.validateGlobalHooks = exports.validatePlan = exports.validatePages = exports.validateFields = exports.validatePageHooks = exports.validateSessionCookieSameSite = exports.validateSessionCookiePath = exports.validateSessionStore = exports.validateSessionSecure = exports.validateSessionName = exports.validateSessionTtl = exports.validateSessionSecret = exports.validateViews = exports.validateSessionObject = exports.validateMountUrl = exports.validateI18nLocales = exports.validateI18nDirs = exports.validateI18nObject = void 0;
|
|
7
|
+
/* eslint-disable sonarjs/no-duplicate-string */
|
|
8
|
+
const field_js_1 = require("./field.js");
|
|
9
|
+
const Plan_js_1 = __importDefault(require("./Plan.js"));
|
|
10
|
+
const logger_js_1 = __importDefault(require("./logger.js"));
|
|
11
|
+
const utils_js_1 = require("./utils.js");
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {import('./index').ContextEvent} ContextEvent
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {object} SessionOptions
|
|
17
|
+
* @property {string} [name=casasession] Session name
|
|
18
|
+
* @property {string} [secret=secret] Encryption secret
|
|
19
|
+
* @property {number} [ttl=3600] Session ttl (seconds)
|
|
20
|
+
* @property {boolean} [secure=false] Whether to use secure session cookies
|
|
21
|
+
* @property {boolean|string} [cookieSameSite=true] SameSite (true = Strict)
|
|
22
|
+
* @property {object} [store] Session store (default MemoryStore)
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {object} I18nOptions
|
|
26
|
+
* @property {string[]} dirs Directories to search for locale dictionaries
|
|
27
|
+
* @property {string[]} [locales=['en', 'cy']] Supported locales
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {object} GlobalHook Hook configuration
|
|
31
|
+
* @property {string} hook Hook name in format `<router>.<hook>`
|
|
32
|
+
* @property {Function} middleware Middleware function to insert at the hook point
|
|
33
|
+
* @property {string|RegExp} [path=undefined] Only run if route path matches this string/regexp
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* @typedef {object} PageHook (extends GlobalHook)
|
|
37
|
+
* @property {string} hook Hook name (without a scope prefix)
|
|
38
|
+
* @property {Function} middleware Middleware function to insert at the hook point
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {object} Page Page configuration. A Page is the interactive representation of a waypoint
|
|
42
|
+
* @property {string} waypoint The waypoint with which this page is associated
|
|
43
|
+
* @property {string} view Template path
|
|
44
|
+
* @property {PageHook[]} [hooks=[]] Page-specific hooks (optional, default [])
|
|
45
|
+
* @property {PageField[]} [fields=[]] Fields to be managed on this page (optional, default [])
|
|
46
|
+
*/
|
|
47
|
+
/**
|
|
48
|
+
* Configure some middleware for use in creating a new CASA app.
|
|
49
|
+
*
|
|
50
|
+
* `mountUrl` is used to ensure the CSS content uses the correct reference to
|
|
51
|
+
* static assets in the `govuk-frontend` module.
|
|
52
|
+
*
|
|
53
|
+
* @typedef {object} ConfigurationOptions Configuration options
|
|
54
|
+
* @property {string} [mountUrl=/] URL path to root of CASA app
|
|
55
|
+
* @property {string[]} [views=[]] Template directories
|
|
56
|
+
* @property {SessionOptions} [session] Session configuration
|
|
57
|
+
* @property {Page[]} [pages=[]] Pages the represent waypoints
|
|
58
|
+
* @property {GlobalHook[]} [hooks=[]] Hooks to apply
|
|
59
|
+
* @property {object[]} [plugins=[]] Plugins
|
|
60
|
+
* @property {I18nOptions[]} [i18n] I18n configuration
|
|
61
|
+
* @property {Plan} plan CASA Plan
|
|
62
|
+
* @property {ContextEvent[]} [events=[]] Handlers for JourneyContext events
|
|
63
|
+
*/
|
|
64
|
+
const log = (0, logger_js_1.default)('lib:configuration-ingestor');
|
|
65
|
+
const echo = (a) => (a);
|
|
66
|
+
/**
|
|
67
|
+
* Validates and sanitises i18n obejct.
|
|
68
|
+
*
|
|
69
|
+
* @param {object} i18n Object to validate.
|
|
70
|
+
* @param {Function} cb Callback function that receives the validated value.
|
|
71
|
+
* @throws {TypeError} For invalid object.
|
|
72
|
+
* @returns {object} Sanitised i18n object.
|
|
73
|
+
*/
|
|
74
|
+
function validateI18nObject(i18n, cb = echo) {
|
|
75
|
+
if (Object.prototype.toString.call(i18n) !== '[object Object]') {
|
|
76
|
+
throw new TypeError('I18n must be an object');
|
|
77
|
+
}
|
|
78
|
+
return cb(i18n);
|
|
79
|
+
}
|
|
80
|
+
exports.validateI18nObject = validateI18nObject;
|
|
81
|
+
/**
|
|
82
|
+
* Validates and sanitises i18n directory.
|
|
83
|
+
*
|
|
84
|
+
* @param {Array} dirs Array of directories.
|
|
85
|
+
* @throws {SyntaxError} For invalid directories.
|
|
86
|
+
* @throws {TypeError} For invalid type.
|
|
87
|
+
* @returns {Array} Array of directories.
|
|
88
|
+
*/
|
|
89
|
+
function validateI18nDirs(dirs) {
|
|
90
|
+
if (typeof dirs === 'undefined') {
|
|
91
|
+
throw ReferenceError('I18n directories are missing (i18n.dirs)');
|
|
92
|
+
}
|
|
93
|
+
else if (!Array.isArray(dirs)) {
|
|
94
|
+
throw new TypeError('I18n directories must be an array (i18n.dirs)');
|
|
95
|
+
}
|
|
96
|
+
dirs.forEach((dir, i) => {
|
|
97
|
+
if (typeof dir !== 'string') {
|
|
98
|
+
throw new TypeError(`I18n directory must be a string, got ${typeof dir} (i18n.dirs[${i}])`);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return dirs;
|
|
102
|
+
}
|
|
103
|
+
exports.validateI18nDirs = validateI18nDirs;
|
|
104
|
+
/**
|
|
105
|
+
* Validates and sanitises i18n locales.
|
|
106
|
+
*
|
|
107
|
+
* @param {Array} locales Array of locales.
|
|
108
|
+
* @throws {SyntaxError} For invalid locales.
|
|
109
|
+
* @throws {TypeError} For invalid type.
|
|
110
|
+
* @returns {Array} Array of locales.
|
|
111
|
+
*/
|
|
112
|
+
function validateI18nLocales(locales) {
|
|
113
|
+
if (typeof locales === 'undefined') {
|
|
114
|
+
throw ReferenceError('I18n locales are missing (i18n.locales)');
|
|
115
|
+
}
|
|
116
|
+
else if (!Array.isArray(locales)) {
|
|
117
|
+
throw new TypeError('I18n locales must be an array (i18n.locales)');
|
|
118
|
+
}
|
|
119
|
+
locales.forEach((locale, i) => {
|
|
120
|
+
if (typeof locale !== 'string') {
|
|
121
|
+
throw new TypeError(`I18n locale must be a string, got ${typeof locale} (i18n.locales[${i}])`);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return locales;
|
|
125
|
+
}
|
|
126
|
+
exports.validateI18nLocales = validateI18nLocales;
|
|
127
|
+
/**
|
|
128
|
+
* Validates and sanitises mount url.
|
|
129
|
+
*
|
|
130
|
+
* @param {string} mountUrl URL from which Express app will be served.
|
|
131
|
+
* @param {string} name Name of the URL type (Mount URL, or Proxy Mount URL).
|
|
132
|
+
* @throws {SyntaxError} For invalid URL.
|
|
133
|
+
* @returns {string} Sanitised URL.
|
|
134
|
+
*/
|
|
135
|
+
function validateMountUrl(mountUrl, name = 'Mount URL') {
|
|
136
|
+
if (typeof mountUrl === 'undefined') {
|
|
137
|
+
return '/';
|
|
138
|
+
}
|
|
139
|
+
if (!mountUrl.match(/\/$/)) {
|
|
140
|
+
throw new SyntaxError(`${name} must include a trailing slash (/)`);
|
|
141
|
+
}
|
|
142
|
+
return mountUrl;
|
|
143
|
+
}
|
|
144
|
+
exports.validateMountUrl = validateMountUrl;
|
|
145
|
+
/**
|
|
146
|
+
* Validates and sanitises sessions object.
|
|
147
|
+
*
|
|
148
|
+
* @param {object} session Object to validate.
|
|
149
|
+
* @param {Function} cb Callback function that receives the validated value.
|
|
150
|
+
* @throws {TypeError} For invalid object.
|
|
151
|
+
* @returns {object} Sanitised sessions object.
|
|
152
|
+
*/
|
|
153
|
+
function validateSessionObject(session, cb = echo) {
|
|
154
|
+
if (session === undefined) {
|
|
155
|
+
return cb(session);
|
|
156
|
+
}
|
|
157
|
+
if (typeof session !== 'object') {
|
|
158
|
+
throw new TypeError('Session config has not been specified');
|
|
159
|
+
}
|
|
160
|
+
return cb(session);
|
|
161
|
+
}
|
|
162
|
+
exports.validateSessionObject = validateSessionObject;
|
|
163
|
+
/**
|
|
164
|
+
* Validates and sanitises view directory.
|
|
165
|
+
*
|
|
166
|
+
* @param {Array} dirs Array of directories.
|
|
167
|
+
* @throws {SyntaxError} For invalid directories.
|
|
168
|
+
* @throws {TypeError} For invalid type.
|
|
169
|
+
* @returns {Array} Array of directories.
|
|
170
|
+
*/
|
|
171
|
+
function validateViews(dirs) {
|
|
172
|
+
if (typeof dirs === 'undefined') {
|
|
173
|
+
throw ReferenceError('View directories are missing (views)');
|
|
174
|
+
}
|
|
175
|
+
else if (!Array.isArray(dirs)) {
|
|
176
|
+
throw new TypeError('View directories must be an array (views)');
|
|
177
|
+
}
|
|
178
|
+
dirs.forEach((dir, i) => {
|
|
179
|
+
if (typeof dir !== 'string') {
|
|
180
|
+
throw new TypeError(`View directory must be a string, got ${typeof dir} (views[${i}])`);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
return dirs;
|
|
184
|
+
}
|
|
185
|
+
exports.validateViews = validateViews;
|
|
186
|
+
/**
|
|
187
|
+
* Validates and sanitises sessions secret.
|
|
188
|
+
*
|
|
189
|
+
* @param {string} secret Session secret.
|
|
190
|
+
* @throws {ReferenceError} For missing value type.
|
|
191
|
+
* @throws {TypeError} For invalid value.
|
|
192
|
+
* @returns {string} Secret.
|
|
193
|
+
*/
|
|
194
|
+
function validateSessionSecret(secret) {
|
|
195
|
+
if (typeof secret === 'undefined') {
|
|
196
|
+
throw ReferenceError('Session secret is missing (sessions.secret)');
|
|
197
|
+
}
|
|
198
|
+
else if (typeof secret !== 'string') {
|
|
199
|
+
throw new TypeError('Session secret must be a string (sessions.secret)');
|
|
200
|
+
}
|
|
201
|
+
return secret;
|
|
202
|
+
}
|
|
203
|
+
exports.validateSessionSecret = validateSessionSecret;
|
|
204
|
+
/**
|
|
205
|
+
* Validates and sanitises sessions ttl.
|
|
206
|
+
*
|
|
207
|
+
* @param {number} ttl Session ttl (seconds).
|
|
208
|
+
* @throws {ReferenceError} For missing value type.
|
|
209
|
+
* @throws {TypeError} For invalid value.
|
|
210
|
+
* @returns {number} Ttl.
|
|
211
|
+
*/
|
|
212
|
+
function validateSessionTtl(ttl) {
|
|
213
|
+
if (typeof ttl === 'undefined') {
|
|
214
|
+
throw ReferenceError('Session ttl is missing (sessions.ttl)');
|
|
215
|
+
}
|
|
216
|
+
else if (typeof ttl !== 'number') {
|
|
217
|
+
throw new TypeError('Session ttl must be an integer (sessions.ttl)');
|
|
218
|
+
}
|
|
219
|
+
return ttl;
|
|
220
|
+
}
|
|
221
|
+
exports.validateSessionTtl = validateSessionTtl;
|
|
222
|
+
/**
|
|
223
|
+
* Validates and sanitises sessions name.
|
|
224
|
+
*
|
|
225
|
+
* @param {string} name Session name.
|
|
226
|
+
* @throws {ReferenceError} For missing value type.
|
|
227
|
+
* @throws {TypeError} For invalid value.
|
|
228
|
+
* @returns {string} Name.
|
|
229
|
+
*/
|
|
230
|
+
function validateSessionName(name) {
|
|
231
|
+
if (typeof name === 'undefined') {
|
|
232
|
+
throw ReferenceError('Session name is missing (sessions.name)');
|
|
233
|
+
}
|
|
234
|
+
else if (typeof name !== 'string') {
|
|
235
|
+
throw new TypeError('Session name must be a string (sessions.name)');
|
|
236
|
+
}
|
|
237
|
+
return name;
|
|
238
|
+
}
|
|
239
|
+
exports.validateSessionName = validateSessionName;
|
|
240
|
+
/**
|
|
241
|
+
* Validates and sanitises sessions secure flag.
|
|
242
|
+
*
|
|
243
|
+
* @param {boolean} secure Session secure flag.
|
|
244
|
+
* @throws {ReferenceError} For missing value type.
|
|
245
|
+
* @throws {TypeError} For invalid value.
|
|
246
|
+
* @returns {string} Name.
|
|
247
|
+
*/
|
|
248
|
+
function validateSessionSecure(secure) {
|
|
249
|
+
if (typeof secure === 'undefined') {
|
|
250
|
+
throw ReferenceError('Session secure flag is missing (sessions.secure)');
|
|
251
|
+
}
|
|
252
|
+
else if (typeof secure !== 'boolean') {
|
|
253
|
+
throw new TypeError('Session secure flag must be boolean (sessions.secure)');
|
|
254
|
+
}
|
|
255
|
+
return secure;
|
|
256
|
+
}
|
|
257
|
+
exports.validateSessionSecure = validateSessionSecure;
|
|
258
|
+
/**
|
|
259
|
+
* Validates and sanitises sessions store.
|
|
260
|
+
*
|
|
261
|
+
* @param {Function} store Session store.
|
|
262
|
+
* @returns {Function} Store.
|
|
263
|
+
*/
|
|
264
|
+
function validateSessionStore(store) {
|
|
265
|
+
if (typeof store === 'undefined') {
|
|
266
|
+
log.warn('Using MemoryStore session storage, which is not suitable for production');
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
return store;
|
|
270
|
+
}
|
|
271
|
+
exports.validateSessionStore = validateSessionStore;
|
|
272
|
+
/**
|
|
273
|
+
* Validates and sanitises sessions cookie url path.
|
|
274
|
+
*
|
|
275
|
+
* @param {string} cookiePath Session cookie url path.
|
|
276
|
+
* @param {string} defaultPath Default path if none specified.
|
|
277
|
+
* @returns {string} Cookie path.
|
|
278
|
+
*/
|
|
279
|
+
function validateSessionCookiePath(cookiePath, defaultPath = '/') {
|
|
280
|
+
if (typeof cookiePath === 'undefined') {
|
|
281
|
+
return defaultPath;
|
|
282
|
+
}
|
|
283
|
+
return cookiePath;
|
|
284
|
+
}
|
|
285
|
+
exports.validateSessionCookiePath = validateSessionCookiePath;
|
|
286
|
+
/**
|
|
287
|
+
* Validates and sanitises sessions cookie "sameSite" flag. One of:
|
|
288
|
+
* true (Strict)
|
|
289
|
+
* false (will not set the flag at all)
|
|
290
|
+
* Strict
|
|
291
|
+
* Lax
|
|
292
|
+
* None
|
|
293
|
+
*
|
|
294
|
+
* @param {any} cookieSameSite Session cookie "sameSite" flag
|
|
295
|
+
* @param {any} defaultFlag Default path if none specified
|
|
296
|
+
* @returns {boolean} cookie path
|
|
297
|
+
* @throws {TypeError} When invalid arguments are provided
|
|
298
|
+
*/
|
|
299
|
+
function validateSessionCookieSameSite(cookieSameSite, defaultFlag) {
|
|
300
|
+
const validValues = [true, false, 'Strict', 'Lax', 'None'];
|
|
301
|
+
if (defaultFlag === undefined) {
|
|
302
|
+
throw new TypeError('validateSessionCookieSameSite() requires an explicit default flag');
|
|
303
|
+
}
|
|
304
|
+
else if (!validValues.includes(defaultFlag)) {
|
|
305
|
+
throw new TypeError('validateSessionCookieSameSite() default flag must be set to one of true, false, Strict, Lax or None (sessions.cookieSameSite)');
|
|
306
|
+
}
|
|
307
|
+
const value = cookieSameSite !== undefined ? cookieSameSite : defaultFlag;
|
|
308
|
+
if (!validValues.includes(value)) {
|
|
309
|
+
throw new TypeError('SameSite flag must be set to one of true, false, Strict, Lax or None (sessions.cookieSameSite)');
|
|
310
|
+
}
|
|
311
|
+
return value;
|
|
312
|
+
}
|
|
313
|
+
exports.validateSessionCookieSameSite = validateSessionCookieSameSite;
|
|
314
|
+
const validatePageHook = (hook, index) => {
|
|
315
|
+
try {
|
|
316
|
+
(0, utils_js_1.validateHookName)(hook.hook);
|
|
317
|
+
if (typeof hook.middleware !== 'function') {
|
|
318
|
+
throw new TypeError('Hook middleware must be a function');
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
err.message = `Page hook at index ${index} is invalid: ${err.message}`;
|
|
323
|
+
throw err;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
function validatePageHooks(hooks) {
|
|
327
|
+
if (!Array.isArray(hooks)) {
|
|
328
|
+
throw new TypeError('Hooks must be an array');
|
|
329
|
+
}
|
|
330
|
+
hooks.forEach((hook, index) => validatePageHook(hook, index));
|
|
331
|
+
return hooks;
|
|
332
|
+
}
|
|
333
|
+
exports.validatePageHooks = validatePageHooks;
|
|
334
|
+
const validateField = (field, index) => {
|
|
335
|
+
try {
|
|
336
|
+
if (!(field instanceof field_js_1.PageField)) {
|
|
337
|
+
throw new TypeError('Page field must be an instance of PageField (created via the "field()" function)');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
catch (err) {
|
|
341
|
+
err.message = `Page field at index ${index} is invalid: ${err.message}`;
|
|
342
|
+
throw err;
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
function validateFields(fields) {
|
|
346
|
+
if (!Array.isArray(fields)) {
|
|
347
|
+
throw new TypeError('Page fields must be an array (page[].fields)');
|
|
348
|
+
}
|
|
349
|
+
fields.forEach((hook, index) => validateField(hook, index));
|
|
350
|
+
return fields;
|
|
351
|
+
}
|
|
352
|
+
exports.validateFields = validateFields;
|
|
353
|
+
const validatePage = (page, index) => {
|
|
354
|
+
try {
|
|
355
|
+
(0, utils_js_1.validateWaypoint)(page.waypoint);
|
|
356
|
+
(0, utils_js_1.validateView)(page.view);
|
|
357
|
+
if (page.fields !== undefined) {
|
|
358
|
+
validateFields(page.fields);
|
|
359
|
+
}
|
|
360
|
+
if (page.hooks !== undefined) {
|
|
361
|
+
validatePageHooks(page.hooks);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
err.message = `Page at index ${index} is invalid: ${err.message}`;
|
|
366
|
+
throw err;
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
function validatePages(pages) {
|
|
370
|
+
if (!Array.isArray(pages)) {
|
|
371
|
+
throw new TypeError('Pages must be an array (pages)');
|
|
372
|
+
}
|
|
373
|
+
pages.forEach((page, index) => validatePage(page, index));
|
|
374
|
+
return pages;
|
|
375
|
+
}
|
|
376
|
+
exports.validatePages = validatePages;
|
|
377
|
+
function validatePlan(plan) {
|
|
378
|
+
if (plan === undefined) {
|
|
379
|
+
return plan;
|
|
380
|
+
}
|
|
381
|
+
if (!(plan instanceof Plan_js_1.default)) {
|
|
382
|
+
throw new TypeError('Plan must be an instance the Plan class (plan)');
|
|
383
|
+
}
|
|
384
|
+
return plan;
|
|
385
|
+
}
|
|
386
|
+
exports.validatePlan = validatePlan;
|
|
387
|
+
const validateGlobalHook = (hook, index) => {
|
|
388
|
+
try {
|
|
389
|
+
(0, utils_js_1.validateHookName)(hook.hook);
|
|
390
|
+
if (typeof hook.middleware !== 'function') {
|
|
391
|
+
throw new TypeError('Hook middleware must be a function');
|
|
392
|
+
}
|
|
393
|
+
if (hook.path !== undefined) {
|
|
394
|
+
(0, utils_js_1.validateHookPath)(hook.path);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
catch (err) {
|
|
398
|
+
err.message = `Global hook at index ${index} is invalid: ${err.message}`;
|
|
399
|
+
throw err;
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
function validateGlobalHooks(hooks) {
|
|
403
|
+
if (hooks === undefined) {
|
|
404
|
+
return [];
|
|
405
|
+
}
|
|
406
|
+
if (!Array.isArray(hooks)) {
|
|
407
|
+
throw new TypeError('Hooks must be an array');
|
|
408
|
+
}
|
|
409
|
+
hooks.forEach((hook, index) => validateGlobalHook(hook, index));
|
|
410
|
+
return hooks;
|
|
411
|
+
}
|
|
412
|
+
exports.validateGlobalHooks = validateGlobalHooks;
|
|
413
|
+
function validatePlugins(plugins) {
|
|
414
|
+
return plugins;
|
|
415
|
+
}
|
|
416
|
+
exports.validatePlugins = validatePlugins;
|
|
417
|
+
function validateEvents(events) {
|
|
418
|
+
return events;
|
|
419
|
+
}
|
|
420
|
+
exports.validateEvents = validateEvents;
|
|
421
|
+
/**
|
|
422
|
+
* Ingest, validate, sanitise and manipulate configuration parameters.
|
|
423
|
+
*
|
|
424
|
+
* @param {ConfigurationOptions} config Config to ingest.
|
|
425
|
+
* @throws {Error|SyntaxError|TypeError} For invalid config values.
|
|
426
|
+
* @returns {object} Immutable config object.
|
|
427
|
+
*/
|
|
428
|
+
function ingest(config = {}) {
|
|
429
|
+
const parsed = {
|
|
430
|
+
// I18n configuration
|
|
431
|
+
i18n: validateI18nObject(config.i18n, (i18n) => ({
|
|
432
|
+
dirs: validateI18nDirs(i18n.dirs),
|
|
433
|
+
locales: validateI18nLocales(i18n.locales),
|
|
434
|
+
})),
|
|
435
|
+
// Public URL from which the app will be served
|
|
436
|
+
mountUrl: validateMountUrl(config.mountUrl),
|
|
437
|
+
// Session
|
|
438
|
+
sessions: validateSessionObject(config.session, (session) => ({
|
|
439
|
+
name: validateSessionName(session.name),
|
|
440
|
+
secret: validateSessionSecret(session.secret),
|
|
441
|
+
secure: validateSessionSecure(session.secure),
|
|
442
|
+
ttl: validateSessionTtl(session.ttl),
|
|
443
|
+
store: validateSessionStore(session.store),
|
|
444
|
+
cookiePath: validateSessionCookiePath(session.cookiePath, '/'),
|
|
445
|
+
cookieSameSite: validateSessionCookieSameSite(session.cookieSameSite, 'Strict'),
|
|
446
|
+
})),
|
|
447
|
+
// Views configuration
|
|
448
|
+
views: validateViews(config.views),
|
|
449
|
+
// Pages
|
|
450
|
+
pages: validatePages(config.pages),
|
|
451
|
+
// Plan
|
|
452
|
+
plan: validatePlan(config.plan),
|
|
453
|
+
// Hooks
|
|
454
|
+
hooks: validateGlobalHooks(config.hooks),
|
|
455
|
+
// Plugins
|
|
456
|
+
plugins: validatePlugins(config.plugins),
|
|
457
|
+
// Events
|
|
458
|
+
events: validateEvents(config.events),
|
|
459
|
+
};
|
|
460
|
+
// Freeze to modifications
|
|
461
|
+
Object.freeze(parsed);
|
|
462
|
+
return parsed;
|
|
463
|
+
}
|
|
464
|
+
exports.default = ingest;
|
|
465
|
+
// module.exports = {
|
|
466
|
+
// ingest,
|
|
467
|
+
// validateAllowPageEdit,
|
|
468
|
+
// validateUseStickyEdit,
|
|
469
|
+
// validateContentSecurityPolicies,
|
|
470
|
+
// validateHeadersObject,
|
|
471
|
+
// validateHeadersDisabled,
|
|
472
|
+
// validateI18nObject,
|
|
473
|
+
// validateI18nDirs,
|
|
474
|
+
// validateI18nLocales,
|
|
475
|
+
// validateMountController,
|
|
476
|
+
// validateMountUrl,
|
|
477
|
+
// validatePhase,
|
|
478
|
+
// validateServiceName,
|
|
479
|
+
// validateSessionExpiryController,
|
|
480
|
+
// validateSessionObject,
|
|
481
|
+
// validateSessionCookiePath,
|
|
482
|
+
// validateSessionCookieSameSite,
|
|
483
|
+
// validateSessionName,
|
|
484
|
+
// validateSessionSecret,
|
|
485
|
+
// validateSessionSecure,
|
|
486
|
+
// validateSessionStore,
|
|
487
|
+
// validateSessionTtl,
|
|
488
|
+
// validateViewsObject,
|
|
489
|
+
// validateViews,
|
|
490
|
+
// };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('express').RequestHandler} ExpressRequestHandler
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {import('./index').MutableRouter} MutableRouter
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('./configuration-ingestor').ConfigurationOptions} ConfigurationOptions
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {object} ConfigureResult Result of a call to configure() function
|
|
12
|
+
* @property {nunjucks.Environment} nunjucksEnv Nunjucks environment
|
|
13
|
+
* @property {MutableRouter} staticRouter Router handling all static assets
|
|
14
|
+
* @property {MutableRouter} ancillaryRouter Router handling ancillary routes
|
|
15
|
+
* @property {MutableRouter} journeyRouter Router handling all waypoint requests
|
|
16
|
+
* @property {ExpressRequestHandler[]} preMiddleware Middleware mounted before anything else
|
|
17
|
+
* @property {ExpressRequestHandler[]} postMiddleware Middleware mounted after everything else
|
|
18
|
+
* @property {ExpressRequestHandler[]} csrfMiddleware CSRF get/set middleware (useful for forms)
|
|
19
|
+
* @property {ExpressRequestHandler} sessionMiddleware Session middleware
|
|
20
|
+
* @property {ExpressRequestHandler[]} cookieParserMiddleware Cookie-parsing middleware
|
|
21
|
+
* @property {ExpressRequestHandler[]} i18nMiddleware I18n preparation middleware
|
|
22
|
+
* @property {ExpressRequestHandler} bodyParserMiddleware Body parsing middleware
|
|
23
|
+
* @property {Function} mount Function used to mount all CASA artifacts onto an ExpressJS app
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Configure some middleware for use in creating a new CASA app.
|
|
27
|
+
*
|
|
28
|
+
* `mountUrl` is used to ensure the CSS content uses the correct reference to
|
|
29
|
+
* static assets in the `govuk-frontend` module.
|
|
30
|
+
*
|
|
31
|
+
* @param {ConfigurationOptions} config Configuration options
|
|
32
|
+
* @returns {ConfigureResult} Result
|
|
33
|
+
*/
|
|
34
|
+
export default function configure(config?: ConfigurationOptions): ConfigureResult;
|
|
35
|
+
export type ExpressRequestHandler = import('express').RequestHandler;
|
|
36
|
+
export type MutableRouter = import('./index').MutableRouter;
|
|
37
|
+
export type ConfigurationOptions = import('./configuration-ingestor').ConfigurationOptions;
|
|
38
|
+
/**
|
|
39
|
+
* Result of a call to configure() function
|
|
40
|
+
*/
|
|
41
|
+
export type ConfigureResult = {
|
|
42
|
+
/**
|
|
43
|
+
* Nunjucks environment
|
|
44
|
+
*/
|
|
45
|
+
nunjucksEnv: nunjucks.Environment;
|
|
46
|
+
/**
|
|
47
|
+
* Router handling all static assets
|
|
48
|
+
*/
|
|
49
|
+
staticRouter: MutableRouter;
|
|
50
|
+
/**
|
|
51
|
+
* Router handling ancillary routes
|
|
52
|
+
*/
|
|
53
|
+
ancillaryRouter: MutableRouter;
|
|
54
|
+
/**
|
|
55
|
+
* Router handling all waypoint requests
|
|
56
|
+
*/
|
|
57
|
+
journeyRouter: MutableRouter;
|
|
58
|
+
/**
|
|
59
|
+
* Middleware mounted before anything else
|
|
60
|
+
*/
|
|
61
|
+
preMiddleware: ExpressRequestHandler[];
|
|
62
|
+
/**
|
|
63
|
+
* Middleware mounted after everything else
|
|
64
|
+
*/
|
|
65
|
+
postMiddleware: ExpressRequestHandler[];
|
|
66
|
+
/**
|
|
67
|
+
* CSRF get/set middleware (useful for forms)
|
|
68
|
+
*/
|
|
69
|
+
csrfMiddleware: ExpressRequestHandler[];
|
|
70
|
+
/**
|
|
71
|
+
* Session middleware
|
|
72
|
+
*/
|
|
73
|
+
sessionMiddleware: ExpressRequestHandler;
|
|
74
|
+
/**
|
|
75
|
+
* Cookie-parsing middleware
|
|
76
|
+
*/
|
|
77
|
+
cookieParserMiddleware: ExpressRequestHandler[];
|
|
78
|
+
/**
|
|
79
|
+
* I18n preparation middleware
|
|
80
|
+
*/
|
|
81
|
+
i18nMiddleware: ExpressRequestHandler[];
|
|
82
|
+
/**
|
|
83
|
+
* Body parsing middleware
|
|
84
|
+
*/
|
|
85
|
+
bodyParserMiddleware: ExpressRequestHandler;
|
|
86
|
+
/**
|
|
87
|
+
* Function used to mount all CASA artifacts onto an ExpressJS app
|
|
88
|
+
*/
|
|
89
|
+
mount: Function;
|
|
90
|
+
};
|