/** * Session license gate — pure decision logic (warn-7 / disable-14 / instant-restore). * * NOTE: the Cursor session-start hook (templates/cursor-hooks/session-start.mjs) * is a standalone script with no access to this package at runtime, so it * MIRRORS this logic inline. These functions are the testable specification — * any change to the thresholds or decisions here MUST be mirrored in the hook * template (and re-installed copies under .cursor/hooks/enterprise-skills/). * * Behavior: * - last validation fresher than 24h -> no network call ("fresh"). * - server says valid -> accept (update timestamp; restore if paused). * - server says KEY_INVALID/KEY_EXPIRED (an explicit NO) -> enforce now. * - network failure / timeout / non-explicit failure -> offline grace: * <7 days since last validation -> silent * 7-13 days -> warn * >=14 days -> enforce */ export declare const REVALIDATE_AFTER_HOURS = 24; export declare const WARN_AFTER_DAYS = 7; export declare const ENFORCE_AFTER_DAYS = 14; export type ValidationOutcome = { kind: "valid"; } | { kind: "invalid"; errorCode?: string; } | { kind: "network_error"; }; export type GateDecision = /** Do nothing (within offline grace, or nothing to do). */ { action: "silent"; } /** Print the offline warning; do not touch any files. */ | { action: "warn"; days: number; message: string; } /** De-render tool-installed skills (move to quarantine, never delete). */ | { action: "enforce"; } /** Validation succeeded: update last_validated_at; restore quarantined skills. */ | { action: "accept"; }; /** Whole days elapsed since `iso`; null when the timestamp is missing/unparseable. */ export declare function daysSince(iso: string | undefined, now: Date): number | null; /** True when the last successful validation is fresher than 24h — skip the network call. */ export declare function isValidationFresh(lastValidatedAt: string | undefined, now: Date): boolean; export declare function formatOfflineWarning(days: number): string; /** * Decide what the session-start gate does after a validation attempt. * * A non-explicit failure (network error, timeout, malformed response, or an * invalid result without KEY_INVALID/KEY_EXPIRED — e.g. a seat conflict) is * deliberately treated as the offline-grace path: only an explicit server NO * about the key enforces immediately. An unparseable/missing last-validation * timestamp is treated as day 0 (silent) — never enforce on unknown data. */ /** Server-truth fields a valid revalidation response may carry (untrusted). */ export interface ValidResponseFields { tier?: unknown; email?: unknown; expires_at?: unknown; seats?: unknown; entitlements?: unknown; } /** * Pure merge of a VALID revalidation response onto the stored license record * — the testable specification the session-start hook mirrors inline, * matching core's repairedLicenseRecord(): the server is the authority on * tier/email/expiry/seats/entitlements; identity fields (key, device_id, * activated_at, telemetry opt-out) never come from the response; only * type-valid fields are taken from the untrusted body. Before this the hook * stamped last_validated_at alone, so org policy reached a healthy cache * only via sync/bundle — the org-policy propagation gap. */ export declare function applyValidResponse(current: Record, data: ValidResponseFields, nowIso?: string): Record; export declare function decideGateAction(outcome: ValidationOutcome, lastValidatedAt: string | undefined, now: Date): GateDecision; //# sourceMappingURL=license-gate.d.ts.map