export interface UserRow { id: string; username: string; tokenHash: string; isAdmin: number; createdAt: string; } export interface DeployQuota { deployId: string; maxBundleBytes: number; maxDiskBytes: number; maxMemoryMb: number; maxCpuPercent: number; } /** Grace window during which a freshly-rotated user's previous token still authenticates. */ export declare const ROTATE_GRACE_MS: number; export declare const DEFAULT_QUOTA: Omit; export declare const ANONYMOUS_QUOTA: Omit; export interface AnonymousDeployRow { deployId: string; claimTokenHash: string; createdAt: string; terminatesAt: string; expiresAt: string; terminated: number; } export interface CustomDomainRow { subdomain: string; deployId: string; createdAt: string; } export interface AuditLogRow { id: number; ts: string; actor: string; action: string; targetDeployId: string | null; targetUserId: string | null; metadata: string | null; } export interface AuditEntry { actor: string; action: string; targetDeployId?: string | null; targetUserId?: string | null; metadata?: Record | null; } export interface ControlDb { hashToken(token: string): string; createUser(username: string, isAdmin: boolean): { user: UserRow; token: string; }; findUserByTokenHash(tokenHash: string): UserRow | null; findUserById(id: string): UserRow | null; findUserByUsername(username: string): UserRow | null; rotateUserToken(userId: string): string; hasAnyUser(): boolean; setDeployOwner(deployId: string, userId: string): void; getDeployOwner(deployId: string): string | null; listDeployIdsForUser(userId: string): string[]; deleteDeployOwner(deployId: string): void; getQuota(deployId: string): DeployQuota; setQuota(deployId: string, patch: Partial>): DeployQuota; deleteQuota(deployId: string): void; createAnonymous(deployId: string, claimToken: string, gracePeriodMs: number, retentionMs: number): { terminatesAt: string; expiresAt: string; }; findAnonymous(deployId: string): AnonymousDeployRow | null; markTerminated(deployId: string): void; listForTermination(nowIso: string): string[]; listForDeletion(nowIso: string): string[]; promoteAnonymous(deployId: string, userId: string): void; deleteAnonymous(deployId: string): void; verifyAnonymousClaim(deployId: string, claimToken: string): boolean; addDomain(subdomain: string, deployId: string): void; findDomain(subdomain: string): CustomDomainRow | null; listDomainsForDeploy(deployId: string): Array<{ subdomain: string; createdAt: string; }>; listDomainsForUser(userId: string): CustomDomainRow[]; countDomainsForUser(userId: string): number; removeDomain(subdomain: string): void; removeDomainsForDeploy(deployId: string): void; /** Per-deploy egress credential + allowlist for the egress proxy. */ setEgress(deployId: string, secretHash: string, allowlist: string[]): void; getEgress(deployId: string): { secretHash: string; allowlist: string[]; } | null; setEgressAllowlist(deployId: string, allowlist: string[]): void; deleteEgress(deployId: string): void; appendAudit(entry: AuditEntry): void; listAudit(opts?: { limit?: number; sinceTs?: string; }): AuditLogRow[]; /** Aggregate deployment counts (from deploy.create audit events): rolling * 24h / 7d windows, all-time total, and a per-day breakdown for the last 7 days. */ deployStats(): { last24h: number; last7d: number; total: number; daily: Array<{ day: string; count: number; }>; }; /** * Records an attempt and returns true if it is within the limit for the * (scope, key) pair over the trailing `windowMs` window. Atomically prunes * entries older than the window. False means the limit is already exhausted * — no attempt is recorded in that case. */ rateAllow(scope: string, key: string, windowMs: number, limit: number): boolean; /** Removes rate-limit entries older than `olderThanMs` from now (across all scopes). */ pruneRateLimits(olderThanMs: number): number; /** * Records one request (and, when `isMutation`, one mutation) against a * deploy's rolling daily quota. Returns ok=false WITHOUT incrementing when the * relevant limit is already reached, so a denied request doesn't consume * quota. `day` is a UTC date key (YYYY-MM-DD). A limit <= 0 disables that axis. */ consumeDailyUsage(deployId: string, day: string, isMutation: boolean, reqLimit: number, mutLimit: number): { ok: boolean; kind?: "request" | "mutation"; }; /** Removes daily-usage rows for days strictly before `beforeDay` (YYYY-MM-DD). */ pruneDailyUsage(beforeDay: string): number; /** * Write a clean, transactionally-consistent snapshot of the control DB to * `destPath` via `VACUUM INTO`. Unlike copying the file, this captures a * coherent state even while the DB is in use (open WAL), so an operator cron * can snapshot a live host without quiescing it. */ backup(destPath: string): void; close(): void; } /** * Verify that a SQLite file at `file` is a usable database, not merely one with * the right magic header. Opens it read-only, runs `PRAGMA integrity_check`, and * confirms the schema is queryable. Used to gate a restore: a candidate that * passes the 16-byte header check can still be truncated/corrupt, and swapping * it in would brick the host on next boot. Returns the failure reason instead of * throwing so callers can turn it into a clean 4xx. */ export declare function validateSqliteFile(file: string): { ok: true; } | { ok: false; error: string; }; export declare function openControlDb(dataDir: string): ControlDb; //# sourceMappingURL=control-db.d.ts.map