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

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

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)
  );
}

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.