Skip to content

Feature library ​

@investec/plugins-feature-library is the main consumer-facing package for feature discovery. It loads feature records, manages favourites, evaluates requirements, applies Adobe Target overrides, and provides search helpers.

Package ​

Warning: By default, this package must be installed only by the platform team into the Investec Online shell application. Do not add it as a direct dependency of a consumer/feature application unless the Web Platform team has explicitly approved that specific use as a rare exception. Consumers should use this plugin's behaviour through the Invsy SDK, or contribute a bounded, governed change to this plugin's own source (see Plugin change governance).

sh
npm install --save @investec/plugins-feature-library

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

What it owns ​

  • feature-registry fetch helpers;
  • favourite add/remove helpers;
  • in-memory customer-context caches for auth, portfolio, and platform data;
  • requirement evaluation based on auth, portfolio, platform, API checks, and customer exclusions;
  • Adobe Target metadata overrides for feature cards;
  • fuzzy search helpers through Fuse.js.

Public contract ​

The main exports are:

  • registry and favourite fetch helpers such as getWebFeatures(...), getMobileFeatures(...), getFavouriteFeatures(...), addFavouriteFeature(...), removeFavouriteFeature(...)
  • context setters such as setFeatureLibraryAuthResponse(...), setFeatureLibraryPortfolio(...), setFeatureLibraryPlatformData(...), setFeatureLibraryClientContext(...)
  • eligibility helpers such as checkFeatureRequirements(...), checkFeatureApiRequirements(...), checkExcludedClientFeatures(...)
  • Adobe Target and search helpers such as checkAdobeTargetActivities(...), featureSearch(...), featureSearchNoStrict(...)

Feature record shape ​

The package expects feature entries shaped like:

ts
interface IFeatureApps {
  key: string;
  value: {
    name: string;
    permissions: string[];
    clientType: string;
    discoverable: boolean;
    requirements: { location: string; flag: string; condition?: string }[];
    apiRequirements: { apiEndpoint?: string; propertyName?: string };
    description: { short: string; full: string };
    media: { icon: string; thumbnail: string; banner: string; region: string };
    tags: string[];
    keywords: string[];
    route: string;
    urlPath: string;
    callToAction: { text: string; target: string };
  };
}

Integration pattern ​

Load registry data:

ts
import { getWebFeatures, setFeatureLibraryAuthResponse, setFeatureLibraryPortfolio, setFeatureLibraryPlatformData, checkFeatureRequirements } from '@investec/plugins-feature-library';

const features = await getWebFeatures('');

setFeatureLibraryAuthResponse(authResponse);
setFeatureLibraryPortfolio(portfolioData);
setFeatureLibraryPlatformData(platformData);

const visible = features.filter((feature) => checkFeatureRequirements(feature.value.requirements, feature.key));

Eligibility model ​

checkFeatureRequirements(...) combines:

  • auth context
  • platform data
  • portfolio data
  • in-memory exclusion results from checkExcludedClientFeatures(...)
  • in-memory API requirement results from checkFeatureApiRequirements(...)

checkFeatureApiRequirements(...) is asynchronous because it performs the feature-specific API calls first. Call it before rendering requirement-sensitive features for a selected profile.

Favourites ​

Favourites are handled through the shared /api/favourites/... routes:

ts
const favourites = await getFavouriteFeatures('', zetaId);
await addFavouriteFeature('', { clientId: zetaId, featureId: feature.key });
await removeFavouriteFeature('', favouriteId);

Adobe Target overrides ​

If a feature entry contains adobeTargetActivity, use checkAdobeTargetActivities(feature, adobeTargetResponse) before rendering the card. The helper mutates the feature metadata to use content from the matching Target activity.

Use the stricter search helper for normal feature-library search:

ts
const results = featureSearch('card', features);

Use featureSearchNoStrict(...) when you intentionally want looser matching, such as "similar features" suggestions.

How consumers extend it ​

Consumers extend this package by composing around the shared eligibility engine, not by reimplementing it.

Common consumer extensions are:

  • pushing additional platform or portfolio context before evaluation;
  • deciding when to run checkFeatureApiRequirements(...) for a selected profile;
  • filtering or ordering the final visible feature list for a page;
  • using Adobe Target overrides for one surface while leaving another unchanged.

Change the package when the shared requirement model itself must change, such as introducing a new requirement source, cache rule, or feature-record contract.

Extension example: build a page-specific feature list ​

ts
import { checkFeatureApiRequirements, checkFeatureRequirements, featureSearch, getWebFeatures, setFeatureLibraryAuthResponse, setFeatureLibraryPlatformData, setFeatureLibraryPortfolio, type IFeatureApps } from '@investec/plugins-feature-library';

type BuildFeatureLibraryParams = {
  authResponse: any;
  portfolioData: any;
  platformData: { isStaff?: boolean };
  profileId?: string;
  searchTerm?: string;
};

export async function buildVisibleFeatureCards({ authResponse, portfolioData, platformData, profileId, searchTerm = '' }: BuildFeatureLibraryParams): Promise<IFeatureApps[]> {
  const allFeatures = await getWebFeatures('');

  setFeatureLibraryAuthResponse(authResponse);
  setFeatureLibraryPortfolio(portfolioData);
  setFeatureLibraryPlatformData(platformData);

  await checkFeatureApiRequirements(allFeatures, profileId);

  const source = searchTerm ? featureSearch(searchTerm, allFeatures) : allFeatures;

  return source.filter((feature) => feature.value.discoverable && checkFeatureRequirements(feature.value.requirements, feature.key));
}

Extend the shared plugin ​

ChangeLocation
Add a feature-registry or favourites API helperfeature-library/src/lib/shared/api-calls.ts
Add an eligibility source or shared rulefeature-library/src/lib/feature-library.ts
Extend the feature or favourite record contractfeature-library/src/lib/types/feature-apps.interface.ts
Add reusable object or search utilitiesfeature-library/src/lib/utilities.ts
Publish the supported additionfeature-library/src/index.ts

For a new API helper, accept the base URL or use the existing platform-relative route pattern, add explicit request and response types, check unsuccessful HTTP responses, and test success and failure with synthetic data.

Contact the Web Platform team before changing eligibility semantics, cache lifecycle, customer exclusions, registry record meaning, favourites ownership, or platform authorisation assumptions.

Consumer notes ​

  • This package keeps several module-level caches in memory for the lifetime of the application.
  • checkFeatureRequirements(...) is synchronous only after the relevant context and API requirement state have already been loaded.
  • Exclusion and API-requirement results are additive caches, so consumers should avoid reusing stale application state across logout boundaries without a full app reset.