Skip to content

Workspace setup and publishing

This repository is an Nx monorepo of publishable plugin libraries. Use this page when you need to work on an existing package, add a new plugin, or build a package for publication.

Prerequisites

  • access to the Investec Azure Artifacts npm feed;
  • a working Node/npm setup compatible with the repository lockfile;
  • permission to publish to the shared package feed when releasing a package.

Clone and install

sh
git clone https://dev.azure.com/investec/client-channel-tech/_git/cxt-channel-investec-plugins
cd cxt-channel-investec-plugins
npm install

Understand the workspace

Each plugin lives at the repository root:

text
menu-builder/
portfolio-builder/
feature-library/
...

A typical package contains:

  • src/index.ts for public exports;
  • src/lib/ for implementation and types;
  • package.json for the published package name and version;
  • project.json for the Nx build target;
  • .azure-pipelines.yml for package publication.

Build a package

Build an individual plugin with Nx:

sh
npx nx build menu-builder

The build output is written to dist/<plugin-name>. For example:

text
dist/menu-builder

To inspect the targets available for a project:

sh
npx nx show project menu-builder

Run the docs site

sh
npm run docs:dev

This serves the VitePress documentation from docs/.

Add a new plugin

Generate a new Nx library with the library generator your team has standardised on, then align it with the conventions used by the existing publishable packages:

  1. place the library at the repository root;
  2. expose the public contract from src/index.ts;
  3. set the published package name in package.json to the form @investec/plugins-my-plugin;
  4. ensure the library has a build target that outputs to dist/my-plugin;
  5. add a package-specific .azure-pipelines.yml.

Package contract guidance

Before publishing a plugin:

  • export only the supported API from src/index.ts;
  • keep package names stable after publication;
  • document mutable state, environment requirements, and reset behaviour;
  • prefer package-root imports in examples and consumers.

When updating a package, be explicit about its extension boundary:

  • what a consumer can vary through inputs, callbacks, or subjects;
  • what a consumer is expected to do after the plugin emits a result;
  • what still requires a package change because it alters shared behaviour.

Shared plugin change standard

Shared plugins are platform contracts, not app-local helpers. When you expand an existing plugin or add a new one, preserve that boundary deliberately.

Treat the plugin as owning:

  • the package-root public API exposed from src/index.ts;
  • shared merge rules, endpoint selection, caches, and state objects;
  • any activeEnvironment switch or documented mutable module-level state;
  • any reset mechanism or lifecycle requirement documented for consumers.

Treat the consumer as owning:

  • application-specific presentation and UI policy;
  • when the plugin runs and what context is injected;
  • how plugin output is persisted into app-owned state;
  • app-only rules that should not automatically affect every consumer.

If the behaviour must remain consistent across multiple consumers, it belongs in the plugin. If it only exists for one application surface, prefer composing around the plugin instead of changing the shared package.

Agent-oriented implementation rules

Agents and contributors should follow these rules when changing a plugin:

  1. preserve the public contract unless the change intentionally introduces a new supported API;
  2. export supported additions from src/index.ts and do not require consumers to import internal file paths;
  3. avoid app-specific business logic in shared packages when the rule belongs in the consuming shell or feature;
  4. document new mutable state, environment requirements, reset behaviour, and extension points in the package page;
  5. prefer extending existing package hooks, inputs, or outputs before adding a parallel helper or duplicate state path;
  6. update examples and related docs whenever the supported usage changes.

Deciding whether to change the plugin

Change the shared package when you need to:

  • add or modify a reusable public export;
  • change shared aggregation, routing, eligibility, or merge behaviour;
  • add a new upstream dependency or package-owned endpoint contract;
  • introduce a reusable extension point needed by more than one consumer;
  • fix a shared bug that consumers should not work around independently.

Do not change the shared package when the requirement is only:

  • page-specific filtering or presentation;
  • one app's analytics naming or UI wording;
  • app-local navigation policy layered on top of the plugin result;
  • one consumer's temporary workaround that should not become the shared default.

Publication model

Each plugin publishes independently through its own Azure pipeline. The usual pattern is:

  1. npm install
  2. npx nx build <plugin>
  3. publish ./dist/<plugin> to the Investec npm feed

Check the package's own .azure-pipelines.yml before assuming branch filters or publication steps, because they differ slightly between packages.

Verification

Before opening a release PR:

  • the target package builds successfully;
  • src/index.ts matches the intended public contract;
  • the package version is correct for the release;
  • the package documentation reflects the shipped API.
  • any changed extension boundary is described clearly enough that another consumer or agent can follow it without reading implementation files first.