@aethex.os/registry
v2.0.1
Published
Plan-based feature gating for SaaS apps — define which features each plan unlocks once, then gate routes, UI, and API endpoints with a single source of truth
Maintainers
Readme
@aethex.os/registry
Plan-based feature gating for SaaS apps. Define which features each plan unlocks once — then enforce it everywhere: React UI, Express routes, page guards.
Install
npm install @aethex.os/registryThe problem
Feature checks scattered across your codebase:
// ❌ This is everywhere
if (user.plan === 'pro' || user.plan === 'enterprise') { ... }
if (user.plan !== 'free') { ... }When you add a new plan, you hunt down every check. When a feature moves tiers, you miss one.
The fix
import { createRegistry } from '@aethex.os/registry';
// ✅ Define once
export const registry = createRegistry({
plans: {
free: ['analytics'],
pro: ['analytics', 'exports', 'api_access', 'team_members'],
enterprise: ['analytics', 'exports', 'api_access', 'team_members', 'sso', 'audit_logs'],
},
});Query from anywhere
registry.can('pro', 'exports') // true
registry.can('free', 'sso') // false
registry.canAll('pro', 'exports', 'sso') // false — needs all
registry.canAny('free', 'exports', 'sso')// false — needs any
registry.features('pro') // ['analytics', 'exports', ...]
registry.plansWith('sso') // ['enterprise']
registry.isAtLeast('pro', 'free') // trueReact
import { RegistryProvider, Gate, useFeature, withFeature } from '@aethex.os/registry';
// Wrap your app
<RegistryProvider registry={registry} plan={user.plan}>
<App />
</RegistryProvider>
// Gate a component
<Gate feature="exports" fallback={<UpgradeBanner />}>
<ExportButton />
</Gate>
// Hook
function Toolbar() {
const canExport = useFeature('exports');
return <button disabled={!canExport}>Export</button>;
}
// HOC
const ExportButton = withFeature('exports', UpgradeBanner)(BaseExportButton);Route protection
const registry = createRegistry({
plans: { ... },
routes: {
'/api/export': { features: ['exports'] },
'/api/admin': { plans: ['enterprise'] },
},
});
registry.canAccessRoute('/api/export', 'free') // false
registry.canAccessRoute('/api/export', 'pro') // trueExpress (with @aethex.os/middleware)
import { createCapabilityGuard } from '@aethex.os/middleware';
app.use(createCapabilityGuard({
realmCapabilities: registry.config.plans,
policies: {
'/api/export': { features: ['exports'] },
},
realmHeader: 'x-user-plan',
}));Part of the @aethex.os ecosystem
See @aethex.os/core for the full package list.
