Skip to main content
Glama
northernvariables

FedMCP - Federal Parliamentary Information

tierLimits.ts10.5 kB
/** * Bookmark Tier Limits and Enforcement * * FREE: 10 bookmarks * BASIC: 100 bookmarks + 10 collections + notes (5000 char limit) * PRO: Unlimited bookmarks + unlimited collections + notes (unlimited) + AI prompts */ export type SubscriptionTier = 'FREE' | 'BASIC' | 'PRO'; export interface TierLimits { maxBookmarks: number | null; // null = unlimited maxCollections: number | null; maxFavorites: number | null; hasAIFeatures: boolean; hasSidebar: boolean; hasExport: boolean; hasBulkOperations: boolean; hasSharing: boolean; // Notes features hasNotes: boolean; // Can add notes to bookmarks maxNoteLength: number | null; // null = unlimited, 0 = disabled hasAIPrompts: boolean; // Can add AI context prompts (PRO only) hasVoiceNotes: boolean; // Can record voice notes (PRO only) hasNoteHistory: boolean; // Can access note version history (PRO only) hasNoteLinks: boolean; // Can link notes to other bookmarks (PRO only) maxWorkspaces: number | null; // Number of workspaces (PRO only) } export const TIER_LIMITS: Record<SubscriptionTier, TierLimits> = { FREE: { maxBookmarks: 10, maxCollections: 0, // No collections for FREE tier maxFavorites: 3, // Quick menu can show 3 favorites hasAIFeatures: false, hasSidebar: false, hasExport: false, hasBulkOperations: false, hasSharing: false, // Notes - locked for FREE tier hasNotes: false, maxNoteLength: 0, hasAIPrompts: false, hasVoiceNotes: false, hasNoteHistory: false, hasNoteLinks: false, maxWorkspaces: 0, }, BASIC: { maxBookmarks: 100, maxCollections: 10, maxFavorites: 10, hasAIFeatures: false, hasSidebar: false, hasExport: true, // Can export to CSV/PDF hasBulkOperations: false, hasSharing: false, // Notes - basic features hasNotes: true, maxNoteLength: 5000, // 5000 character limit hasAIPrompts: false, hasVoiceNotes: false, hasNoteHistory: false, hasNoteLinks: false, maxWorkspaces: 0, }, PRO: { maxBookmarks: null, // Unlimited maxCollections: null, // Unlimited maxFavorites: null, // Unlimited hasAIFeatures: true, // AI suggestions, connections, summaries, alerts hasSidebar: true, // Sidebar panel on all pages hasExport: true, hasBulkOperations: true, hasSharing: true, // Share collections publicly // Notes - all features unlocked hasNotes: true, maxNoteLength: null, // Unlimited hasAIPrompts: true, // Can add AI context prompts hasVoiceNotes: true, // Can record voice notes hasNoteHistory: true, // Can access note version history hasNoteLinks: true, // Can link notes with [[notation]] maxWorkspaces: null, // Unlimited workspaces }, }; /** * Get tier limits for a user */ export function getTierLimits(tier?: string | null): TierLimits { const normalizedTier = (tier?.toUpperCase() || 'FREE') as SubscriptionTier; return TIER_LIMITS[normalizedTier] || TIER_LIMITS.FREE; } /** * Check if user can create more bookmarks */ export function canCreateBookmark( currentCount: number, tier?: string | null ): boolean { const limits = getTierLimits(tier); if (limits.maxBookmarks === null) return true; // Unlimited return currentCount < limits.maxBookmarks; } /** * Check if user can create more collections */ export function canCreateCollection( currentCount: number, tier?: string | null ): boolean { const limits = getTierLimits(tier); if (limits.maxCollections === null) return true; // Unlimited if (limits.maxCollections === 0) return false; // Not allowed for this tier return currentCount < limits.maxCollections; } /** * Check if user can create more favorites */ export function canCreateFavorite( currentCount: number, tier?: string | null ): boolean { const limits = getTierLimits(tier); if (limits.maxFavorites === null) return true; // Unlimited return currentCount < limits.maxFavorites; } /** * Get user-friendly limit message */ export function getLimitMessage( type: 'bookmark' | 'collection' | 'favorite', tier?: string | null ): string { const limits = getTierLimits(tier); const tierName = tier || 'FREE'; switch (type) { case 'bookmark': if (limits.maxBookmarks === null) { return `You have unlimited bookmarks with ${tierName} tier`; } return `You've reached your bookmark limit (${limits.maxBookmarks} for ${tierName} tier)`; case 'collection': if (limits.maxCollections === 0) { return `Collections are not available on ${tierName} tier. Upgrade to BASIC or PRO to organize your bookmarks.`; } if (limits.maxCollections === null) { return `You have unlimited collections with ${tierName} tier`; } return `You've reached your collection limit (${limits.maxCollections} for ${tierName} tier)`; case 'favorite': if (limits.maxFavorites === null) { return `You have unlimited favorites with ${tierName} tier`; } return `You've reached your favorites limit (${limits.maxFavorites} for ${tierName} tier)`; default: return `Limit reached for ${tierName} tier`; } } /** * Check if user can add/edit notes */ export function canUseNotes(tier?: string | null): boolean { const limits = getTierLimits(tier); return limits.hasNotes; } /** * Check if note length is within tier limit */ export function isNoteWithinLimit( noteLength: number, tier?: string | null ): boolean { const limits = getTierLimits(tier); if (!limits.hasNotes) return false; if (limits.maxNoteLength === null) return true; // Unlimited return noteLength <= limits.maxNoteLength; } /** * Get remaining note characters */ export function getRemainingNoteChars( noteLength: number, tier?: string | null ): number | null { const limits = getTierLimits(tier); if (!limits.hasNotes) return 0; if (limits.maxNoteLength === null) return null; // Unlimited return Math.max(0, limits.maxNoteLength - noteLength); } /** * Get note character limit message */ export function getNoteLimitMessage( noteLength: number, tier?: string | null ): string { const limits = getTierLimits(tier); if (!limits.hasNotes) { return 'Notes are not available on FREE tier. Upgrade to BASIC or PRO.'; } if (limits.maxNoteLength === null) { return `${noteLength.toLocaleString()} characters (unlimited)`; } const remaining = limits.maxNoteLength - noteLength; if (remaining < 0) { return `Over limit by ${Math.abs(remaining).toLocaleString()} characters`; } return `${noteLength.toLocaleString()} / ${limits.maxNoteLength.toLocaleString()} characters`; } /** * Get upgrade message for a specific feature */ export function getUpgradeMessage( feature: 'bookmark' | 'collection' | 'ai' | 'sidebar' | 'export' | 'bulk' | 'sharing' | 'notes' | 'ai-prompts' | 'voice-notes' | 'note-history' | 'workspaces', currentTier?: string | null ): { message: string; targetTier: SubscriptionTier } { const tier = (currentTier?.toUpperCase() || 'FREE') as SubscriptionTier; switch (feature) { case 'bookmark': if (tier === 'FREE') { return { message: 'Upgrade to BASIC for 100 bookmarks or PRO for unlimited', targetTier: 'BASIC', }; } return { message: 'Upgrade to PRO for unlimited bookmarks', targetTier: 'PRO', }; case 'collection': if (tier === 'FREE') { return { message: 'Upgrade to BASIC or PRO to create collections', targetTier: 'BASIC', }; } return { message: 'Upgrade to PRO for unlimited collections', targetTier: 'PRO', }; case 'ai': return { message: 'Upgrade to PRO for AI-powered insights, connections, and smart alerts', targetTier: 'PRO', }; case 'sidebar': return { message: 'Upgrade to PRO for the always-accessible bookmark sidebar', targetTier: 'PRO', }; case 'export': if (tier === 'FREE') { return { message: 'Upgrade to BASIC or PRO to export your bookmarks', targetTier: 'BASIC', }; } return { message: 'Export is included in your plan', targetTier: tier, }; case 'bulk': return { message: 'Upgrade to PRO for bulk operations', targetTier: 'PRO', }; case 'sharing': return { message: 'Upgrade to PRO to share collections publicly', targetTier: 'PRO', }; case 'notes': if (tier === 'FREE') { return { message: 'Upgrade to BASIC for note-taking or PRO for unlimited notes + AI features', targetTier: 'BASIC', }; } return { message: 'Upgrade to PRO for unlimited note length and AI-powered features', targetTier: 'PRO', }; case 'ai-prompts': return { message: 'Upgrade to PRO to add AI context prompts to your notes', targetTier: 'PRO', }; case 'voice-notes': return { message: 'Upgrade to PRO to record voice notes', targetTier: 'PRO', }; case 'note-history': return { message: 'Upgrade to PRO to access note version history', targetTier: 'PRO', }; case 'workspaces': return { message: 'Upgrade to PRO to create workspaces for organizing your research', targetTier: 'PRO', }; default: return { message: 'Upgrade to unlock this feature', targetTier: 'PRO', }; } } /** * Calculate bookmark usage stats */ export interface BookmarkUsageStats { total: number; limit: number | null; percentage: number; isNearLimit: boolean; // >= 80% isAtLimit: boolean; canCreate: boolean; } export function getBookmarkUsageStats( currentCount: number, tier?: string | null ): BookmarkUsageStats { const limits = getTierLimits(tier); const { maxBookmarks } = limits; if (maxBookmarks === null) { // Unlimited return { total: currentCount, limit: null, percentage: 0, isNearLimit: false, isAtLimit: false, canCreate: true, }; } const percentage = (currentCount / maxBookmarks) * 100; return { total: currentCount, limit: maxBookmarks, percentage, isNearLimit: percentage >= 80, isAtLimit: currentCount >= maxBookmarks, canCreate: currentCount < maxBookmarks, }; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/northernvariables/FedMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server