/** * Lemma API v2 — PlanPolicy (Lane D) * * Replaces `src/cloud/types.ts` PLAN_LIMITS. Quota is measured by ACTIVE-VERIFIED * memories and by SEAT, not only by request count, and `Infinity` is gone — * every plan has an explicit, positive ceiling. Exceeding a cap yields a 429 * with an actionable body: limit, current use, reset time and upgrade link. * * This module owns the plan table. The DB migration only stores tenancy; keeping * a second copy of the limits in SQL would guarantee drift. */ export type PlanId = 'free' | 'pro' | 'scale'; export interface PlanLimits { /** Active AND verified memories the tenant may keep. */ activeMemories: number; /** Concurrent seats (API keys / members) the tenant may hold. */ seats: number; /** Requests allowed per rate-limit window. */ dailyRequests: number; /** Requests allowed per calendar month. */ monthlyRequests: number; /** Length of the rate-limit window (24h = UTC-day buckets). */ rateLimitWindowMs: number; /** Where the client is pointed when a cap is hit. */ upgradeUrl: string; } export declare const RATE_LIMIT_WINDOW_MS: number; export declare const PLAN_UPGRADE_URL: Readonly>; /** Single source of truth for plan ceilings. Every value finite and > 0. */ export declare const PLAN_LIMITS: Readonly>; export declare const DEFAULT_PLAN: PlanId; /** * The `Infinity` elimination check, exported so tests can prove it (and the * policy constructor refuses any non-finite/zero ceiling at startup). */ export declare function validatePlanLimits(limits: Record): string[]; export type QuotaKind = 'memories' | 'seats'; export interface QuotaViolation { kind: QuotaKind; plan: PlanId; limit: number; current: number; upgradeUrl: string; message: string; } export type QuotaCheck = { allowed: true; } | { allowed: false; violation: QuotaViolation; }; /** The actionable 429 body for quota_exceeded (additive to the LemmaApiError envelope). */ export interface QuotaErrorBody { error: { code: 'quota_exceeded'; status: 429; message: string; plan: PlanId; kind: QuotaKind; limit: number; current: number; /** When the counter resets, or null when there is no scheduled reset (memory quotas). */ resetsAt: number | null; upgradeUrl: string; }; } export declare function quotaErrorBody(violation: QuotaViolation, resetsAt?: number | null): QuotaErrorBody; export declare class PlanPolicy { private readonly limits; constructor(limits?: Record); /** Limits for a plan; unknown plans conservatively fall back to `free`. */ limitsFor(plan: string): PlanLimits; /** Memory quota: number of ACTIVE-VERIFIED memories the plan allows. */ checkMemoryQuota(planId: string, activeVerifiedMemories: number): QuotaCheck; /** Seat quota: number of seats (members/keys) the plan allows. */ checkSeatQuota(planId: string, seats: number): QuotaCheck; private checkStatic; } //# sourceMappingURL=PlanPolicy.d.ts.map