@dwp/govuk-casa 8.2.4 → 8.2.5

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 CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [8.2.5](https://github.com/dwp/govuk-casa/compare/8.2.3...8.2.5) (2022-06-01)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * serve statics correctly from deeply nested apps ([0fd00a5](https://github.com/dwp/govuk-casa/commit/0fd00a5f10de28706afe87a993072d3184e3c7aa))
11
+
5
12
  ### [8.2.3](https://github.com/dwp/govuk-casa/compare/8.2.2...8.2.3) (2022-05-23)
6
13
 
7
14
  ### [8.2.2](https://github.com/dwp/govuk-casa/compare/8.2.1...8.2.2) (2022-05-23)
package/dist/casa.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type PageField = import('./lib/field').PageField;
2
- export type ContextEventHandler = (journeyContext: JourneyContext, previousContext: JourneyContext) => void;
2
+ export type ContextEventHandler = (opts: object, journeyContext: JourneyContext, previousContext: JourneyContext, session: object) => void;
3
3
  export type ContextEvent = {
4
4
  /**
5
5
  * Waypoint to watch for changes
@@ -108,13 +108,14 @@ export type IPlugin = {
108
108
  /**
109
109
  * Modify the app config
110
110
  */
111
- configure?: Function | undefined;
111
+ configure?: PluginConfigureFunction | undefined;
112
112
  /**
113
113
  * Modify post-configuration artifacts
114
114
  */
115
- bootstrap?: Function | undefined;
115
+ bootstrap?: PluginBootstrapFunction | undefined;
116
116
  };
117
- export type PluginConfigureFunction = (config: object) => any;
117
+ export type PluginConfigureFunction = (config: ConfigurationOptions) => any;
118
+ export type PluginBootstrapFunction = (config: ConfigureResult) => any;
118
119
  export type HelmetConfigurator = (config: object) => object;
119
120
  export type Mounter = (app: import('express').Express, opts: object, route?: string | undefined) => import('express').Express;
120
121
  export type MutableRouter = import('./lib/index').MutableRouter;
@@ -153,11 +154,15 @@ export type ConfigurationOptions = {
153
154
  /**
154
155
  * CASA Plan
155
156
  */
156
- plan: Plan;
157
+ plan?: Plan | undefined;
157
158
  /**
158
159
  * Handlers for JourneyContext events
159
160
  */
160
161
  events?: ContextEvent[] | undefined;
162
+ /**
163
+ * Helmet configuration manipulator function
164
+ */
165
+ helmetConfigurator?: HelmetConfigurator | undefined;
161
166
  };
162
167
  /**
163
168
  * Result of a call to configure() function
@@ -211,6 +216,10 @@ export type ConfigureResult = {
211
216
  * Function used to mount all CASA artifacts onto an ExpressJS app
212
217
  */
213
218
  mount: Mounter;
219
+ /**
220
+ * Ingested config supplied to `configure()`
221
+ */
222
+ config: ConfigurationOptions;
214
223
  };
215
224
  /**
216
225
  * Configuration for generating a ValidationError.
package/dist/casa.js CHANGED
@@ -55,8 +55,10 @@ exports.nunjucksFilters = nunjucksFilters;
55
55
  */
56
56
  /**
57
57
  * @callback ContextEventHandler
58
- * @param {JourneyContext} journeyContext Context including changes
59
- * @param {JourneyContext} previousContext Context prior to changes
58
+ * @param {object} opts Options
59
+ * @param {JourneyContext} opts.journeyContext Context including changes
60
+ * @param {JourneyContext} opts.previousContext Context prior to changes
61
+ * @param {object} opts.session Request session object
60
62
  * @returns {void}
61
63
  */
62
64
  /**
@@ -99,12 +101,16 @@ exports.nunjucksFilters = nunjucksFilters;
99
101
  */
100
102
  /**
101
103
  * @typedef {object} IPlugin Plugin interface
102
- * @property {Function} [configure] Modify the app config
103
- * @property {Function} [bootstrap] Modify post-configuration artifacts
104
+ * @property {PluginConfigureFunction} [configure] Modify the app config
105
+ * @property {PluginBootstrapFunction} [bootstrap] Modify post-configuration artifacts
104
106
  */
105
107
  /**
106
108
  * @callback PluginConfigureFunction
107
- * @param {object} config Options
109
+ * @param {ConfigurationOptions} config Options
110
+ */
111
+ /**
112
+ * @callback PluginBootstrapFunction
113
+ * @param {ConfigureResult} config Options
108
114
  */
109
115
  /**
110
116
  * @callback HelmetConfigurator
@@ -115,7 +121,7 @@ exports.nunjucksFilters = nunjucksFilters;
115
121
  * @callback Mounter
116
122
  * @param {import('express').Express} app Express application
117
123
  * @param {object} opts Mounting options
118
- * @param {string} [opts.route=/] Optional route to attach all middleware/routers too
124
+ * @param {string} [opts.route='/'] Optional route to attach all middleware/routers too
119
125
  * @returns {import('express').Express} The prepared ExpressJS app instance
120
126
  */
121
127
  /**
@@ -132,8 +138,9 @@ exports.nunjucksFilters = nunjucksFilters;
132
138
  * @property {GlobalHook[]} [hooks=[]] Hooks to apply
133
139
  * @property {IPlugin[]} [plugins=[]] Plugins
134
140
  * @property {I18nOptions[]} [i18n] I18n configuration
135
- * @property {Plan} plan CASA Plan
141
+ * @property {Plan} [plan] CASA Plan
136
142
  * @property {ContextEvent[]} [events=[]] Handlers for JourneyContext events
143
+ * @property {HelmetConfigurator} [helmetConfigurator] Helmet configuration manipulator function
137
144
  */
138
145
  /**
139
146
  * @typedef {object} ConfigureResult Result of a call to configure() function
@@ -149,6 +156,7 @@ exports.nunjucksFilters = nunjucksFilters;
149
156
  * @property {import('express').RequestHandler[]} i18nMiddleware I18n preparation middleware
150
157
  * @property {import('express').RequestHandler} bodyParserMiddleware Body parsing middleware
151
158
  * @property {Mounter} mount Function used to mount all CASA artifacts onto an ExpressJS app
159
+ * @property {ConfigurationOptions} config Ingested config supplied to `configure()`
152
160
  */
153
161
  /**
154
162
  * Configuration for generating a ValidationError.
@@ -466,10 +466,19 @@ class JourneyContext {
466
466
  * @returns {void}
467
467
  */
468
468
  static initContextStore(session) {
469
+ // For existing sessions that were created prior to `journeyContextList`
470
+ // being remodelled as an array, we need to convert the "legacy" structure
471
+ // into an equivalent array.
472
+ if (isPlainObject(session === null || session === void 0 ? void 0 : session.journeyContextList)) {
473
+ log.trace('Session context list already initialised as an object (legacy structure). Will convert from object to array.');
474
+ /* eslint-disable-next-line no-param-reassign */
475
+ session.journeyContextList = Object.entries(session.journeyContextList);
476
+ }
477
+ // Initialise new context list in the session
469
478
  if (!has(session, 'journeyContextList')) {
470
479
  log.trace('Initialising session with a default journey context list');
471
480
  /* eslint-disable-next-line no-param-reassign */
472
- session.journeyContextList = Object.create(null);
481
+ session.journeyContextList = [];
473
482
  const defaultContext = new JourneyContext();
474
483
  defaultContext.identity.id = JourneyContext.DEFAULT_CONTEXT_ID;
475
484
  JourneyContext.putContext(session, defaultContext);
@@ -515,10 +524,11 @@ class JourneyContext {
515
524
  * @returns {JourneyContext} The discovered JourneyContext instance
516
525
  */
517
526
  static getContextById(session, id) {
518
- if (has(session === null || session === void 0 ? void 0 : session.journeyContextList, id)) {
527
+ const list = new Map(session === null || session === void 0 ? void 0 : session.journeyContextList);
528
+ if (list.has(id)) {
519
529
  // ESLint disabled as `id` has been verified as an "own" property
520
530
  /* eslint-disable-next-line security/detect-object-injection */
521
- return JourneyContext.fromObject(session.journeyContextList[id]);
531
+ return JourneyContext.fromObject(list.get(id));
522
532
  }
523
533
  return undefined;
524
534
  }
@@ -531,7 +541,8 @@ class JourneyContext {
531
541
  */
532
542
  static getContextByName(session, name) {
533
543
  if (session) {
534
- const context = Object.values(session.journeyContextList).find((c) => (c.identity.name === name));
544
+ const list = new Map(session === null || session === void 0 ? void 0 : session.journeyContextList);
545
+ const context = [...list.values()].find((c) => (c.identity.name === name));
535
546
  if (context) {
536
547
  return JourneyContext.fromObject(context);
537
548
  }
@@ -547,7 +558,8 @@ class JourneyContext {
547
558
  */
548
559
  static getContextsByTag(session, tag) {
549
560
  if (session) {
550
- return Object.values(session.journeyContextList).filter((c) => { var _a; return ((_a = c.identity.tags) === null || _a === void 0 ? void 0 : _a.includes(tag)); }).map((c) => (JourneyContext.fromObject(c)));
561
+ const list = new Map(session === null || session === void 0 ? void 0 : session.journeyContextList);
562
+ return [...list.values()].filter((c) => { var _a; return ((_a = c.identity.tags) === null || _a === void 0 ? void 0 : _a.includes(tag)); }).map((c) => (JourneyContext.fromObject(c)));
551
563
  }
552
564
  return undefined;
553
565
  }
@@ -559,7 +571,7 @@ class JourneyContext {
559
571
  */
560
572
  static getContexts(session) {
561
573
  if (has(session, 'journeyContextList')) {
562
- return Object.values(session.journeyContextList).map((contextObj) => (JourneyContext.fromObject(contextObj)));
574
+ return session.journeyContextList.map(([, contextObj]) => (JourneyContext.fromObject(contextObj)));
563
575
  }
564
576
  return [];
565
577
  }
@@ -594,8 +606,10 @@ class JourneyContext {
594
606
  event: 'context-change',
595
607
  session,
596
608
  });
609
+ const list = new Map(session.journeyContextList);
610
+ list.set(context.identity.id, context.toObject());
597
611
  /* eslint-disable-next-line no-param-reassign */
598
- session.journeyContextList[context.identity.id] = context.toObject();
612
+ session.journeyContextList = [...list.entries()];
599
613
  }
600
614
  /**
601
615
  * Remove a context from the session store.
@@ -617,10 +631,10 @@ class JourneyContext {
617
631
  * @returns {void}
618
632
  */
619
633
  static removeContextById(session, id) {
620
- if (session && has(session.journeyContextList, id)) {
621
- // ESLint disabled as `id` has been verified as an "own" property
622
- /* eslint-disable-next-line security/detect-object-injection, no-param-reassign */
623
- delete session.journeyContextList[id];
634
+ var _a;
635
+ const index = ((_a = session === null || session === void 0 ? void 0 : session.journeyContextList) !== null && _a !== void 0 ? _a : []).findIndex(([contextId]) => contextId === id);
636
+ if (index > -1) {
637
+ session.journeyContextList.splice(index, 1);
624
638
  }
625
639
  }
626
640
  /**
@@ -51,6 +51,7 @@ function configure(config = {}) {
51
51
  plugin.configure(config);
52
52
  });
53
53
  // Extract config
54
+ const ingestedConfig = (0, configuration_ingestor_js_1.default)(config);
54
55
  const { mountUrl, views = [], session = {
55
56
  secret: 'secret',
56
57
  name: 'casasession',
@@ -62,7 +63,7 @@ function configure(config = {}) {
62
63
  }, pages = [], plan = null, hooks = [], plugins = [], events = [], i18n = {
63
64
  dirs: [],
64
65
  locales: ['en', 'cy'],
65
- }, helmetConfigurator = undefined, } = (0, configuration_ingestor_js_1.default)(config);
66
+ }, helmetConfigurator = undefined, } = ingestedConfig;
66
67
  // Prepare all page hooks so they are prefixed with the `journey.` scope.
67
68
  pages.forEach((page) => {
68
69
  var _a;
@@ -214,6 +215,8 @@ function configure(config = {}) {
214
215
  dataMiddleware,
215
216
  // Mount function
216
217
  mount,
218
+ // Ingested config
219
+ config: ingestedConfig,
217
220
  };
218
221
  // Bootstrap all plugins
219
222
  plugins.filter((p) => p.bootstrap).forEach((plugin) => plugin === null || plugin === void 0 ? void 0 : plugin.bootstrap(configOutput));
package/dist/lib/utils.js CHANGED
@@ -148,7 +148,7 @@ function validateHookName(hookName) {
148
148
  if (!hookName.length) {
149
149
  throw new SyntaxError('Hook name must not be empty');
150
150
  }
151
- if (!hookName.match(/^([a-z]+\.|)[a-z]+$/i)) {
151
+ if (!hookName.match(/^([a-z_]+\.|)[a-z_]+$/i)) {
152
152
  throw new SyntaxError('Hook name must match either <scope>.<hookname> or <hookname> formats');
153
153
  }
154
154
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dwp/govuk-casa",
3
- "version": "8.2.4",
3
+ "version": "8.2.5",
4
4
  "description": "A framework for building GOVUK Collect-And-Submit-Applications",
5
5
  "repository": {
6
6
  "type": "git",