Skip to content

Menu builder ​

@investec/plugins-menu-builder is the menu aggregation layer for Investec Online. It decides which menu endpoints to call from auth context, merges the responses into one IMenuConfig, and maps menu IDs to region-specific URLs.

Package ​

Warning: This package must be installed only by the platform team into the Investec Online shell application. Never add it as a direct dependency of a consumer/feature application. Consumers use this plugin's behaviour through the Invsy SDK, or by contributing a bounded, governed change to this plugin's own source (see Plugin change governance).

sh
npm install --save @investec/plugins-menu-builder

The platform owns installation of released plugin versions. A consuming team normally contributes shared menu logic in this repository and then asks the platform team to adopt the published version.

What it owns ​

  • auth-driven menu endpoint selection
  • merge logic for menu trees and menu items without children
  • region-aware URL configuration through menuItemMap
  • incremental menu updates through menuBuilder.updateAppState
  • per-call success/failure tracking in callResultMap

Public contract ​

The main package-root exports include:

  • menuBuilder
  • setupMenu()
  • aggregateMenuItems(...)
  • aggregateClientProfileFlagsMenuItems(...)
  • MenuUrlMap() and AdditionalClientProfileFlagsMenuUrlMap()
  • menu types such as IMenuConfig, IMenuItem
  • config exports such as menuItemMap

Integration pattern ​

ts
import { menuBuilder, setupMenu } from '@investec/plugins-menu-builder';

menuBuilder.activeEnvironment = 'staging';
menuBuilder.authResponse.next(authResponse);

menuBuilder.updateAppState.subscribe((menuConfig) => {
  // Persist or pass the menu config onward.
});

await setupMenu();

Result shape ​

The aggregated menu config includes:

ts
interface IMenuConfig {
  mainMenu: IMenuItem[];
  mainMenuWithoutChildren: IMenuItem[];
  callResultMap: { url: string; result: boolean; region: string }[];
  hasError?: boolean;
  currentMenuRegion?: string;
}

Runtime behaviour ​

setupMenu():

  1. derives the active menu region from auth context
  2. chooses menu endpoints from MenuUrlMap() and AdditionalClientProfileFlagsMenuUrlMap()
  3. fetches and merges menu payloads
  4. fills missing URLs through menuItemMap
  5. updates menuBuilder.updateAppState as data arrives

The default Profile & settings links use /usrroot-wpaas/update-login-details, /usrroot-wpaas/security-questions, and /usrroot-wpaas/website-settings. These are routes within app-platform-user, not separate applications. configureMenuItem() only fills an AbsoluteUrl that is null; it does not replace an explicit default-menu URL. Keep these paths free of stray quotes: the shell URL-encodes them, so a trailing " becomes %22 and changes the route.

How consumers extend it ​

Consumers normally extend menu behaviour after the plugin emits its canonical menu model.

Typical patterns are:

  • subscribe to menuBuilder.updateAppState and persist the result in app state;
  • choose when to call setupMenu() based on auth lifecycle;
  • update the current region in app state before dependent consumers render;
  • decorate the built menu for one shell surface without changing the shared aggregation rules.

Change the package when a new menu endpoint, new auth-driven call rule, or new shared URL mapping is needed.

Extension example: decorate the canonical menu in app state ​

ts
import { menuBuilder, setupMenu, type IMenuConfig } from '@investec/plugins-menu-builder';

type DecoratedMenuState = {
  menuConfig: IMenuConfig;
  hasVisibleItems: boolean;
};

let latestMenuState: DecoratedMenuState | undefined;

menuBuilder.activeEnvironment = 'staging';
menuBuilder.authResponse.next(authResponse);

menuBuilder.updateAppState.subscribe((menuConfig) => {
  latestMenuState = {
    menuConfig,
    hasVisibleItems: menuConfig.mainMenu.length > 0 || menuConfig.mainMenuWithoutChildren.length > 0,
  };
});

await setupMenu();

Extend the shared plugin ​

ChangeLocation
Add an auth-driven menu APIMenuUrlMap() or AdditionalClientProfileFlagsMenuUrlMap() in configs/menu-configs.ts
Add an environment-specific endpointmenu-builder/src/lib/environment.ts
Map a menu ID to a shared routemenuItemMap in configs/menu-configs.ts
Change shared fetch, merge, or error trackingmenu-builder/src/lib/menu-builder.ts
Extend the public modelmenu-builder/src/lib/types/ and src/index.ts

When adding an API, define its auth flag, region, URL, environment differences, headers, merge behaviour, and failure result. Add tests for selected and unselected auth contexts, duplicate menu data, failed calls, and URL mapping.

Contact the Web Platform team before changing menu ownership, default menu behaviour, shared merge semantics, authentication headers, or a route used by multiple client types.

Consumer notes ​

  • The package keeps module-level state and expects authResponse to be pushed in before setupMenu().
  • URL mapping is coupled to menu-item IDs and the current region.
  • clearState.next() resets the current config back to the default empty menu.
  • hasError is raised through callResultMap updates when one or more menu calls fail.