Skip to content

Portfolio builder ​

@investec/plugins-portfolio-builder retrieves the portfolios allowed by the authenticated client context, stores them in a shared state object, and keeps net-worth totals up to date.

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-portfolio-builder

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

What it owns ​

  • environment-aware portfolio endpoint selection
  • direct fetch helpers for individual portfolio types
  • aggregate state in portfolioBuilder
  • totals calculation across included portfolios
  • optional exclusions from totals
  • streamed multi-portfolio loading through getAllPortfoliosStream(...)

Public contract ​

The main package-root exports include:

  • portfolioBuilder
  • portfolio
  • portfolio types such as IPortfolioEntity

portfolioBuilder contains:

  • activeEnvironment
  • profileSwitch
  • updateAppState
  • currentPortfolioState
  • authResponse
  • clearState

Integration pattern ​

Set the environment and auth context first:

ts
import { portfolio, portfolioBuilder } from '@investec/plugins-portfolio-builder';

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

portfolioBuilder.updateAppState.subscribe((state) => {
  // Persist or forward portfolio state.
});

Use direct fetch methods when you need one portfolio:

ts
await portfolio.getPrivateBankZAPortfolio('ZAR', profileId);

Use the streaming method when a shell or SDK host needs the full aggregate flow:

ts
portfolio.getAllPortfoliosStream(target);

target must match the exported HookTarget shape and provide source.postMessage(...).

Runtime behaviour ​

Direct methods such as getPrivateBankZAPortfolio(...), getPrivateBankUKPortfolio(...), getWealthAndInvestmentZAPortfolio(...), getAllNonInvestecAccounts(...), and the other portfolio-specific methods:

  • fetch the relevant endpoint
  • merge the response into currentPortfolioState
  • update totals
  • push the new state through updateAppState

getAllPortfoliosStream(...) orchestrates those methods from auth context and posts intermediate and final results through target.source.postMessage(...) using __id: 'portfolio.stream'.

State shape ​

The aggregate state includes:

  • portfolios
  • totals
  • callResultMap
  • currency
  • contactData
  • excludes

Totals are recalculated whenever portfolios or exclusions change.

How consumers extend it ​

Consumers extend this package through orchestration and post-processing:

  • push authResponse and selected-profile context before calling portfolio methods;
  • call direct portfolio methods when only one portfolio family is needed;
  • use getAllPortfoliosStream(...) when a host needs incremental updates;
  • use UpdatePortfolioExcludes(...) to change which loaded portfolios contribute to totals;
  • persist or transform the emitted state for product-specific rendering.

Change the package when a new portfolio family, endpoint, contact-data rule, or shared aggregation rule is needed.

Extension example: load one portfolio family and exclude it from totals ​

ts
import { portfolio, portfolioBuilder, type IPortfolioEntity } from '@investec/plugins-portfolio-builder';

let latestPortfolioState: IPortfolioEntity | undefined;

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

portfolioBuilder.updateAppState.subscribe((state) => {
  latestPortfolioState = state;
});

await portfolio.getPrivateBankZAPortfolio('ZAR', selectedProfileId);

await portfolio.UpdatePortfolioExcludes([{ flag: 'PrivateBankZA', result: true }]);

console.log(latestPortfolioState?.totals);

Extend the shared plugin ​

ChangeLocation
Add an environment-specific portfolio endpoint or switchportfolio-builder/src/lib/environment.ts
Add a direct portfolio or contact-data callportfolio in portfolio-builder/src/lib/portfolio-builder.ts
Include a new portfolio in the aggregate streamgetAllPortfoliosStream(...) orchestration
Extend aggregate state or contact dataportfolio-builder/src/lib/types/portfolio.interface.ts
Publish the supported additionportfolio-builder/src/index.ts

A new portfolio API must define its auth flag, profile and currency inputs, headers, response mapping, state key, call-result behaviour, totals inclusion, and stream completion behaviour. Add tests for eligible and ineligible auth contexts, API failure, profile switching, exclusions, and totals.

Contact the Web Platform team before changing net-worth calculations, shared currency semantics, stream message protocol, customer-data handling, or the meaning of an existing portfolio field.

Consumer notes ​

  • profileSwitch affects how the selected profile data is interpreted by the aggregate streaming flow.
  • Some portfolio methods also populate contactData.
  • UpdatePortfolioExcludes(...) changes which portfolios contribute to totals; it does not delete the portfolio payload itself.
  • clearState.next() resets both the current portfolio state and the cached auth response.