/** * Engine: Redis-like semantics, type checks, expiration, cache coordination. */ import { KEY_TYPES } from '../storage/sqlite/schema.ts'; import type Database from '../storage/sqlite/driver.ts'; import type { Cache, CacheValues } from '../cache/cache.ts'; import type { BlockingManager } from '../blocking/manager.ts'; import type { KeyMeta } from '../storage/sqlite/keys.ts'; import type { SearchOptions } from '../storage/sqlite/search.ts'; export interface EngineOptions { db: Database; cache?: Cache | null; clock?: () => number; /** FT.SEARCH guards. */ search?: SearchOptions; } /** Keys, fields, members and values accept strings and are stored as Buffers. */ export type KeyInput = Buffer | string; /** Raw numeric argument parsed by the engine. */ export type NumericInput = Buffer | string | number; export type HashFieldExpireCondition = 'NX' | 'XX' | 'GT' | 'LT'; export interface SetOptions { expiresAt?: number | bigint | null; ex?: NumericInput | bigint; px?: NumericInput | bigint; exat?: NumericInput | bigint; pxat?: NumericInput | bigint; nx?: boolean; xx?: boolean; get?: boolean; keepttl?: boolean; } export interface HscanOptions { count?: number; match?: Buffer | string | null; noValues?: boolean; } export interface ScanOptions { count?: number; } export interface ZsetRangeOptions { withScores?: boolean; } export interface ZsetScoreRangeOptions { withScores?: boolean; offset?: number; limit?: number; } export declare function createEngine(opts: EngineOptions): { get(key: KeyInput): Buffer | null; strlen(key: KeyInput): number; set(key: KeyInput, value: KeyInput, options?: SetOptions): { written: boolean; previous: Buffer | null; }; setnx(key: KeyInput, value: KeyInput): number; mset(pairs: KeyInput[]): void; msetnx(pairs: KeyInput[]): 0 | 1; mget(keysList: KeyInput[]): (Buffer | null)[]; del(keysToDelete: KeyInput[]): number; exists(keysToCheck: KeyInput[]): number; dbsize(): number; flushDatabase(): void; expire(key: KeyInput, seconds: number): boolean; pexpire(key: KeyInput, milliseconds: number): boolean; ttl(key: KeyInput): number | bigint; pttl(key: KeyInput): number | bigint; persist(key: KeyInput): boolean; incr(key: KeyInput): number; decr(key: KeyInput): number; incrby(key: KeyInput, delta: number): number; decrby(key: KeyInput, delta: number): number; hset(key: KeyInput, ...pairs: KeyInput[]): number; hsetnx(key: KeyInput, field: KeyInput, value: KeyInput): number; hget(key: KeyInput, field: KeyInput): Buffer | null; hmget(key: KeyInput, fields: KeyInput[]): (Buffer | null)[]; hgetall(key: KeyInput): Buffer[]; hkeys(key: KeyInput): Buffer[]; hvals(key: KeyInput): Buffer[]; hstrlen(key: KeyInput, field: KeyInput): number; hscan(key: KeyInput, cursor: number, options?: HscanOptions): { cursor: number; values: Buffer[]; }; hrandfield(key: KeyInput, count?: number | null, { withValues }?: { withValues?: boolean; }): Buffer[] | Buffer | null; hdel(key: KeyInput, fields: KeyInput[]): number; hlen(key: KeyInput): number; hexists(key: KeyInput, field: KeyInput): number; hincrby(key: KeyInput, field: KeyInput, amount: NumericInput): number; hincrbyfloat(key: KeyInput, field: KeyInput, amount: NumericInput): Buffer; /** * HEXPIRE: apply absolute expiresAtMs to each hash field with optional NX/XX/GT/LT. * Returns an array of integers per spec: -2 (missing), 0 (cond), 1 (set), 2 (deleted). */ hexpire(key: KeyInput, expiresAtMs: number, fields: KeyInput[], { condition }?: { condition?: HashFieldExpireCondition | null; }): number[]; /** * HTTL: seconds remaining per field. -2 missing, -1 no TTL, else seconds. */ httl(key: KeyInput, fields: KeyInput[]): number[]; hpttl(key: KeyInput, fields: KeyInput[]): number[]; hexpiretime(key: KeyInput, fields: KeyInput[], { milliseconds }?: { milliseconds?: boolean; }): number[]; /** * HPERSIST: clear field TTL. -2 missing, -1 no TTL, 1 cleared. */ hpersist(key: KeyInput, fields: KeyInput[]): number[]; sadd(key: KeyInput, ...members: KeyInput[]): number; srem(key: KeyInput, members: KeyInput[]): number; smembers(key: KeyInput): Buffer[]; sismember(key: KeyInput, member: KeyInput): 0 | 1; smismember(key: KeyInput, members: KeyInput[]): number[]; scard(key: KeyInput): number; spop(key: KeyInput, count?: number | null): Buffer[] | Buffer | null; srandmember(key: KeyInput, count?: number | null): Buffer[] | Buffer | null; lpush(key: KeyInput, ...values: KeyInput[]): number; rpush(key: KeyInput, ...values: KeyInput[]): number; llen(key: KeyInput): number; lrange(key: KeyInput, start: NumericInput, stop: NumericInput): Buffer[]; lindex(key: KeyInput, index: NumericInput): Buffer | null; lpop(key: KeyInput, count?: number | null): Buffer[] | Buffer | null; rpop(key: KeyInput, count?: number | null): Buffer[] | Buffer | null; lmpop(keysToCheck: KeyInput[], direction: string, count: number): [Buffer, Buffer[]] | null; lrem(key: KeyInput, count: NumericInput, element: KeyInput): number; lset(key: KeyInput, index: NumericInput, value: KeyInput): void; ltrim(key: KeyInput, start: NumericInput, stop: NumericInput): void; zadd(key: KeyInput, scoreMemberPairs: KeyInput[]): number; zrem(key: KeyInput, members: KeyInput[]): number; zcard(key: KeyInput): number; zscore(key: KeyInput, member: KeyInput): string | null; zmscore(key: KeyInput, members: KeyInput[]): (string | null)[]; zmpop(keysToCheck: KeyInput[], direction: string, count: number): [Buffer, [Buffer, string][]] | null; zrange(key: KeyInput, start: number, stop: number, options?: ZsetRangeOptions): (string | Buffer)[]; zrevrange(key: KeyInput, start: number, stop: number, options?: ZsetRangeOptions): (string | Buffer)[]; zrevrank(key: KeyInput, member: KeyInput): number | null; zrank(key: KeyInput, member: KeyInput): number | null; zrangebyscore(key: KeyInput, min: number, max: number, options?: ZsetScoreRangeOptions): (string | Buffer)[]; zcount(key: KeyInput, min: number, max: number): number; zincrby(key: KeyInput, increment: NumericInput, member: KeyInput): string; zremrangebyrank(key: KeyInput, start: NumericInput, stop: NumericInput): number; zremrangebyscore(key: KeyInput, min: NumericInput, max: NumericInput): number; zrevrangebyscore(key: KeyInput, max: number, min: number, options?: ZsetScoreRangeOptions): (string | Buffer)[]; type(key: KeyInput): string; /** * OBJECT IDLETIME: seconds since key was last written (updated_at). * Returns null if key does not exist (Redis: nil). */ objectIdletime(key: KeyInput): number | null; /** * MEMORY USAGE: bytes of key name plus stored payload. Null if key does not exist. */ memoryUsage(key: KeyInput): number | null; /** Keyspace summary for INFO: live keys, keys with TTL, mean TTL in ms. */ keyspaceInfo(): { keys: number; expires: number; avgTtlMs: number; }; databaseBytes(): number; scan(cursor: string | number, options?: ScanOptions): { cursor: number; keys: Buffer[]; }; rename(key: KeyInput, newkey: KeyInput): void; runScript(fn: () => T): T; /** * Run fn in one write transaction (nested engine transactions become savepoints). * On failure nothing fn wrote is kept, so the cache is cleared with it. */ runBatch(fn: () => T): T; _db: Database; _cache: { get(key: string): import("../cache/cache.ts").CacheEntry | null; set(key: string, kind: K, value: CacheValues[K], version: number, expiresAt: number | bigint | null): void; invalidate(key: string): void; clear(): void; limits: Readonly<{ maxHashFields: number; maxHashBytes: number; maxSetMembers: number; maxSetBytes: number; maxListItems: number; maxListBytes: number; maxZsetMembers: number; maxZsetBytes: number; }>; readonly stats: { entries: number; bytes: number; hits: number; misses: number; hitRatio: number; enabled: boolean; }; } | null; _keys: { KEY_TYPES: { STRING: number; HASH: number; SET: number; LIST: number; ZSET: number; }; get(key: Buffer): KeyMeta | null; set(key: Buffer, type: number, options?: import("../storage/sqlite/keys.ts").KeySetOptions): void; setExpires(key: Buffer, expiresAt: number | bigint | null, updatedAt?: number): void; bumpVersion(key: Buffer): void; setSetCount(key: Buffer, setCount: number, options?: import("../storage/sqlite/keys.ts").CountUpdateOptions): void; incrSetCount(key: Buffer, delta: number, options?: import("../storage/sqlite/keys.ts").CountUpdateOptions): void; setHashCount(key: Buffer, hashCount: number, options?: import("../storage/sqlite/keys.ts").CountUpdateOptions): void; incrHashCount(key: Buffer, delta: number, options?: import("../storage/sqlite/keys.ts").CountUpdateOptions): void; setZsetCount(key: Buffer, zsetCount: number, options?: import("../storage/sqlite/keys.ts").CountUpdateOptions): void; incrZsetCount(key: Buffer, delta: number, options?: import("../storage/sqlite/keys.ts").CountUpdateOptions): void; delete(key: Buffer): import("node:sqlite").StatementResultingChanges; deleteAll(): number | bigint; deleteExpired(now: number): import("node:sqlite").StatementResultingChanges; count(): number; countLive(now: number): number; scan(limit: number, offset: number): Buffer[]; }; _strings: { get(key: Buffer): Buffer | null; set(key: Buffer, value: Buffer, options?: import("../storage/sqlite/strings.ts").StringSetOptions): void; setMultiple(entries: { key: Buffer; value: Buffer; options?: import("../storage/sqlite/strings.ts").StringSetOptions; }[]): void; delete(key: Buffer): void; copyKey(oldKey: Buffer, newKey: Buffer): void; }; _hashes: { get(key: Buffer, field: Buffer): Buffer | null; getAll(key: Buffer): Buffer[]; getAllWithMeta: (key: Buffer) => { values: Buffer[]; hasFieldTtl: boolean; }; scan(key: Buffer, limit: number, offset: number): Buffer[]; set(key: Buffer, field: Buffer, value: Buffer, options?: import("../storage/sqlite/hashes.ts").HashWriteOptions): number; setMultiple(key: Buffer, pairs: Buffer[], options?: import("../storage/sqlite/hashes.ts").HashWriteOptions): number; setIfAbsent(key: Buffer, field: Buffer, value: Buffer, options?: import("../storage/sqlite/hashes.ts").HashWriteOptions): number; delete(key: Buffer, fields: Buffer[], options?: import("../storage/sqlite/hashes.ts").HashWriteOptions): number; count(key: Buffer, options?: import("../storage/sqlite/hashes.ts").HashWriteOptions): number; incr(key: Buffer, field: Buffer, delta: number, options?: import("../storage/sqlite/hashes.ts").HashWriteOptions): number; incrFloat(key: Buffer, field: Buffer, delta: number, options?: import("../storage/sqlite/hashes.ts").HashWriteOptions): Buffer; setFieldExpire(key: Buffer, field: Buffer, expiresAtMs: number, { condition }?: { condition?: 'NX' | 'XX' | 'GT' | 'LT' | null; }): number; getFieldTtl(key: Buffer, field: Buffer): { value: number; expired: boolean; }; getFieldExpireAt(key: Buffer, field: Buffer): { value: number; expired: boolean; }; persistField(key: Buffer, field: Buffer): number; copyKey(oldKey: Buffer, newKey: Buffer): void; }; _sets: { add(key: Buffer, members: Buffer[], options?: { updatedAt?: number; }): number; remove(key: Buffer, members: Buffer[]): number; members(key: Buffer): Buffer[]; has(key: Buffer, member: Buffer): boolean; count(key: Buffer): number; copyKey(oldKey: Buffer, newKey: Buffer): void; getRandomMembers(key: Buffer, count: number | null | undefined): Buffer | Buffer[] | null; popRandom(key: Buffer, count: number | null | undefined, options?: { updatedAt?: number; }): Buffer | Buffer[] | null; }; _lists: { lpush(key: Buffer, values: Buffer[], options?: { updatedAt?: number; }): number; rpush(key: Buffer, values: Buffer[], options?: { updatedAt?: number; }): number; llen(key: Buffer): number; lrange(key: Buffer, start: number, stop: number): Buffer[]; lindex(key: Buffer, index: number): Buffer | null; lpop(key: Buffer, count?: number | null): Buffer | Buffer[] | null; rpop(key: Buffer, count?: number | null): Buffer | Buffer[] | null; lrem(key: Buffer, count: number, element: Buffer | string): number; lset(key: Buffer, index: number, value: Buffer): void; ltrim(key: Buffer, start: number, stop: number): void; copyKey(oldKey: Buffer, newKey: Buffer): void; }; _zsets: { add(key: Buffer, pairs: { score: number; member: Buffer; }[], options?: { updatedAt?: number; }): number; remove(key: Buffer, members: Buffer[]): number; count(key: Buffer): number; score(key: Buffer, member: Buffer): string | null; rangeByRank(key: Buffer, start: number, stop: number, options?: import("../storage/sqlite/zsets.ts").ZsetRangeOptions): (Buffer | string)[]; rangeByRankReverse(key: Buffer, start: number, stop: number, options?: import("../storage/sqlite/zsets.ts").ZsetRangeOptions): (Buffer | string)[]; rangeByScore(key: Buffer, min: number, max: number, options?: import("../storage/sqlite/zsets.ts").ZsetScoreRangeOptions): (Buffer | string)[]; rankReverse(key: Buffer, member: Buffer): number | null; rank(key: Buffer, member: Buffer): number | null; rangeByScoreReverse(key: Buffer, max: number, min: number, options?: import("../storage/sqlite/zsets.ts").ZsetScoreRangeOptions): (Buffer | string)[]; copyKey(oldKey: Buffer, newKey: Buffer): void; countByScore(key: Buffer, min: number, max: number): number; incr(key: Buffer, member: Buffer, increment: number, options?: { updatedAt?: number; }): string; removeRangeByRank(key: Buffer, start: number, stop: number): number; removeRangeByScore(key: Buffer, min: number, max: number): number; }; _clock: () => number; _searchLimits: Required; _blockingManager: BlockingManager | null; }; export { KEY_TYPES }; export type Engine = ReturnType;