shared-features — a project by Ahsan Mahmood
NPM TypeScript/React library that centralizes feature flags, cross-promotion advertising, in-app broadcasts, and 9 profile-data domains, administered from…
This package started as copy-and-paste.
The same three systems kept turning up in every product I shipped. A feature flag, so a half-finished screen could go out dark. A banner pointing at whichever of my own products was relevant to the person looking. An announcement channel for the times something needs saying inside the application rather than by email.
Three systems, rewritten each time, drifting apart each time.
The drift is the expensive part. A flag that respects the installed version in one product and ignores it in another is two behaviours wearing one name, and the day that difference matters is a day you are already busy debugging something else.
shared-features is what those three became once.
Feature flags here are version-aware, so a flag can be on for the build that can handle it and off for the build that cannot. That is the difference between a flag and a switch. A switch assumes everybody is running today's version, and nobody is.
Cross-promotion is the second system, with impression tracking attached, because an advertisement nobody counts is a decoration.
Broadcasts, announcements and alerts are the third. Nine profile-data domains sit beside them, covering contact, developer, social, address, payment, services, skills and testimonials among others, which are the shapes a profile keeps needing in product after product.
All of it is administered from one panel.
A banner, an advertisement or a flag changes in one place and reaches every application consuming the package. The alternative is a release in each product for a change of copy, which in practice means the copy stays wrong.
What it cost is the thing that makes a shared library different from a private one.
You cannot break your own consumers.
The package holds a deprecate-before-remove contract, so a minor version never takes anything away, and a decision you have come to regret keeps living behind a deprecation notice until a major release earns the right to delete it.
That is a tax on every design mistake, paid in public.
React, Firebase, Radix and Zustand stay peers rather than dependencies, so nothing gets bundled twice and the consuming application keeps deciding its own versions. Six subpath entry points mean a project importing only the flags never carries the advertising code.
The build is dual ESM and CommonJS with type declarations, produced through Vite's library mode. That is the least interesting sentence on this page and it is the one that decides whether the package drops cleanly into somebody else's toolchain or becomes an afternoon.
It is a live dependency in ZTools and in this portfolio.
That is the honest form of the maintenance answer. The first application to break when I get something wrong is one of mine, usually within a day, usually while I am doing something else.
It is not a support promise. It is the reason a defect tends to surface before anybody else has to find it.
There is no iOS release behind this work, because there is no Apple Developer account here. The companion website is wrapped with Capacitor for Android, with telemetry and Sentry behind it.
On npm as shared-features. The source is at github.com/aoneahsan/shared-features.
The reason to read it is not the feature list. It is that the plumbing underneath three separate products is now one thing, in one place, written down where anybody can open it and decide whether they agree with how it works.
What it does, and what that costs to build
- Version-aware feature flags
- Cross-promotion advertising with impression tracking
- In-app broadcasts/announcements/alerts
- 9 shared profile-data domains
- One Firestore admin console for all consumers
- Dual ESM + CJS + .d.ts (6 subpath entry points)
- Deprecate-before-remove backward-compat contract
Built with
- TypeScript
- React 19
- Vite 8
- Radix UI Themes
- Firebase
- Zustand
Worth knowing
- npm
- package
- feature-flags
- react
- firebase
- reusable-infrastructure
Who built shared-features?
Ahsan Mahmood built it for his own products first, which is the useful thing to know about it. It is on npm as shared-features, with the source at github.com/aoneahsan/shared-features, and it is a live dependency in ZTools and in this portfolio site. So the first application to break when something in it is wrong is one of his own, which is a different quality of testing from a suite that only ever runs on a laptop. That is not a support promise and should not be read as one.
What is actually in it?
Three production systems and a set of shared profile shapes. The systems are version-aware feature flags, cross-product advertising campaigns with impression tracking, and in-app broadcasts with announcements and alerts. Beside them sit nine profile-data domains covering contact, developer, social, address, payment, services, skills and testimonials among others, which are the shapes that kept being rebuilt product after product. The through-line is that each of those had been written more than once before this package existed, and each copy had quietly drifted into slightly different behaviour.
Does shared-features work on iPhone?
It is a React library, so it runs inside whatever your application runs in, an iPhone browser included, and there is nothing platform-specific in it. There is no iOS release behind any of this work, because there is no Apple Developer account here and nothing I build has shipped to the App Store. The companion website is wrapped with Capacitor for Android. The accurate statement is that the code is portable and the released mobile surface is Android alone.
Where is it administered from?
From one admin panel, so a flag, a banner or an announcement is changed once and reaches every application consuming the package. That is the whole reason it exists as a library rather than as three copied folders. Without it, changing a line of promotional copy means a release in every product that shows it, which in practice means the copy stays wrong for months. The data sits in Firestore behind that panel, and the consuming applications read it instead of each holding a copy of their own.
Will a minor version break my build?
No, and that is a written contract rather than an intention. The package holds a deprecate-before-remove rule: a minor release never takes anything away, and something regretted keeps working behind a deprecation notice until a major version earns the right to remove it. Keeping React, Firebase, Radix and Zustand as peers helps as well, because nothing is bundled twice and your application keeps deciding its own versions of them. The cost of that contract falls on the library rather than on you, which is the correct side for it to sit.
https://aoneahsan.com/projects/com.aoneahsan.sharedfeatures