@harperfast/rocksdb-js 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +299 -14
- package/dist/index.cjs +513 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +524 -15
- package/dist/index.d.mts +524 -15
- package/dist/index.mjs +511 -16
- package/dist/index.mjs.map +1 -1
- package/docs/stats.md +309 -268
- package/package.json +19 -20
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["FRESH_VERSION_FLAG","resolvePath","FRESH_VERSION_FLAG","#sink","#finalized","#remaining","#pad","#includeValues","#limit","#yielded","#claimed","#txn","#handleCommitError","#name","MsgpackEncoder","#abortTransaction","#abandonTransaction","TRANSACTION_LOG_ENTRY_HEADER_SIZE"],"sources":["../src/load-binding.ts","../src/validate-transaction-log.ts","../src/backup.ts","../src/util.ts","../src/dbi.ts","../src/tar.ts","../src/backup-stream.ts","../src/dbi-iterator.ts","../src/encoding.ts","../src/store.ts","../src/transaction.ts","../src/database.ts","../src/parse-transaction-log.ts","../src/transaction-log-reader.ts","../src/index.ts"],"sourcesContent":["import type { BackupInfo, BackupOptions, RestoreOptions } from './backup.js';\nimport type { RangeOptions } from './dbi.js';\nimport type { BufferWithDataView, Key } from './encoding.js';\nimport type { StatsAll, StatsDefault, StatsHistogramData } from './stats.js';\nimport type { StoreContext } from './store.js';\nimport type { TransactionLogStoreValidation } from './validate-transaction-log.js';\nexport type {\n\tGetStatsMethod,\n\tStatsAll,\n\tStatsAllExtras,\n\tStatsBasics,\n\tStatsCurated,\n\tStatsCuratedExtras,\n\tStatsDefault,\n\tStatsHistogramData,\n\tStatsValue,\n} from './stats.js';\nimport { execSync } from 'node:child_process';\nimport { readdirSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nexport type NativeTransactionOptions = {\n\t/**\n\t * Whether to disable snapshots.\n\t *\n\t * @default false\n\t */\n\tdisableSnapshot?: boolean;\n\n\t/**\n\t * When `true`, an `IsBusy` conflict at commit time is resolved with the\n\t * `RETRY_NOW` sentinel value instead of being rejected. The native layer\n\t * may park on a VT slot before resolving, so the JS retry fires only after\n\t * the conflicting transaction has committed and released its write intent.\n\t *\n\t * Use together with `verificationTable: true` on the database.\n\t *\n\t * @default false\n\t */\n\tcoordinatedRetry?: boolean;\n};\n\nexport type NativeTransaction = {\n\tid: number;\n\tnew (context: NativeDatabase, options?: NativeTransactionOptions): NativeTransaction;\n\tabandonWrites(): void;\n\tabort(): void;\n\tcommit(resolve: (retrySignal?: number) => void, reject: (err: Error) => void): void;\n\tcommitSync(): void;\n\t// Note that keyLengthOrKeyBuffer can be the length of the key if it was written into the shared buffer, or a direct buffer\n\tget(\n\t\tkeyLengthOrKeyBuffer: number | Buffer,\n\t\tresolve: (value: Buffer | number) => void,\n\t\treject: (err: Error) => void,\n\t\ttxnIdIgnored?: number,\n\t\texpectedVersion?: number\n\t): number;\n\tgetCount(options?: RangeOptions): number;\n\tgetSync(keyLengthOrKeyBuffer: number | Buffer): Buffer | number | undefined;\n\tgetTimestamp(): number;\n\tputSync(key: Key, value: Buffer | Uint8Array, txnId?: number): void;\n\tremoveSync(key: Key): void;\n\tsetTimestamp(timestamp?: number): void;\n\tuseLog(name: string | number): TransactionLog;\n};\n\nexport type LogBuffer = Buffer & {\n\tdataView: DataView;\n\tlogId: number;\n\tsize: number;\n};\n\nexport type TransactionLogQueryOptions = {\n\tstart?: number;\n\tend?: number;\n\texactStart?: boolean;\n\tstartFromLastFlushed?: boolean;\n\treadUncommitted?: boolean;\n\texclusiveStart?: boolean;\n};\n\nexport type TransactionEntry = {\n\ttimestamp: number;\n\tdata: Buffer;\n\tendTxn: boolean;\n};\n\n/**\n * A position within a transaction log, identifying a log file by its sequence\n * number and a byte `offset` within that file.\n */\nexport type TransactionLogPosition = { sequence: number; offset: number };\n\n/**\n * A detailed statistics snapshot for a single transaction log store, returned\n * by {@link TransactionLog.getStats}. All sizes are in bytes; timestamps are\n * milliseconds since the Unix epoch.\n *\n * Memory note: `memory.mappedBytes` is virtual address space — the active write\n * file is mapped at the full configured `maxFileSize` on POSIX, so it does not\n * reflect resident memory. `memory.overlayBytes` (POSIX only; 0 on Windows) is\n * the file-backed portion and is the closer proxy for real consumption.\n */\nexport type TransactionLogStats = {\n\tname: string;\n\tpath: string;\n\tfileCount: number;\n\tcurrentSequenceNumber: number;\n\toldestSequenceNumber: number;\n\ttotalSizeBytes: number;\n\tcurrentFileSize: number;\n\tpendingTransactions: number;\n\tuncommittedTransactions: number;\n\treplayGapBytes: number;\n\tmemory: {\n\t\tmappedBytes: number;\n\t\toverlayBytes: number;\n\t\tactiveMaps: number;\n\t};\n\tnextLogPosition: TransactionLogPosition;\n\tlastFlushedPosition: TransactionLogPosition;\n\tlastCommittedPosition: TransactionLogPosition | null;\n\tpurge: {\n\t\toldestFileAgeMs: number;\n\t\tpurgeableFiles: number;\n\t\tretainedUnflushedFiles: number;\n\t\tlastPurgeMs: number;\n\t};\n\ttotals: {\n\t\ttransactionsWritten: number;\n\t\tentriesWritten: number;\n\t\tbytesWritten: number;\n\t\trotations: number;\n\t\tfilesPurged: number;\n\t\tbytesPurged: number;\n\t\tpurgeRuns: number;\n\t\tdatabaseFlushes: number;\n\t\twriteFailures: number;\n\t};\n\tconfig: {\n\t\tmaxFileSize: number;\n\t\tretentionMs: number;\n\t\tmaxAgeThreshold: number;\n\t};\n};\n\nexport type TransactionLog = {\n\tnew (db: NativeDatabase, name: string): TransactionLog;\n\taddEntry(data: Buffer | Uint8Array, txnId?: number): void;\n\tgetLogFileSize(sequenceId?: number): number;\n\tgetStats(): TransactionLogStats;\n\tname: string;\n\tpath: string;\n\tquery(options?: TransactionLogQueryOptions): IterableIterator<TransactionEntry>;\n\t_currentLogBuffer: LogBuffer;\n\t_findPosition(timestamp: number): number;\n\t_getLastCommittedPosition(): Buffer;\n\t_getLastFlushed(): number;\n\t_getMemoryMapOfFile(sequenceId: number): LogBuffer | undefined;\n\t_lastCommittedPosition: Float64Array;\n\t_logBuffers: Map<number, WeakRef<LogBuffer>>;\n};\n\n/**\n * Shape of options that can be passed to the native iterator constructor for\n * the rare case of advanced RocksDB ReadOptions overrides. Common iterator\n * options are passed via the bitmask `flags` argument instead.\n */\nexport type NativeIteratorAdvancedOptions = {\n\tadaptiveReadahead?: boolean;\n\tasyncIO?: boolean;\n\tautoReadaheadSize?: boolean;\n\tbackgroundPurgeOnIteratorCleanup?: boolean;\n\tfillCache?: boolean;\n\treadaheadSize?: number;\n\ttailing?: boolean;\n};\n\n/**\n * The result of a single native iterator step. A number value matches one of\n * the `ITERATOR_RESULT_*` constants. The slow-path object is returned when\n * the data does not fit in the shared key/value buffers, or when the decoder\n * needs a stable value buffer.\n */\nexport type NativeIteratorResult = number | { key: Buffer; value?: Buffer };\n\nexport declare class NativeIteratorCls {\n\tconstructor(\n\t\tcontext: StoreContext,\n\t\tflags: number,\n\t\tstartKeyEnd: number,\n\t\tendKeyStart: number,\n\t\tendKeyEnd: number,\n\t\toptions?: NativeIteratorAdvancedOptions\n\t);\n\tnext(): NativeIteratorResult;\n\treturn(): void;\n\tthrow(err?: unknown): void;\n}\n\nexport type NativeDatabaseMode = 'optimistic' | 'pessimistic';\n\nexport type NativeDatabaseOptions = {\n\t/**\n\t * The friendly name of a compression algorithm compiled into this RocksDB\n\t * build (see `supportedCompression`), e.g. `'lz4'`, `'zstd'`, `'none'`. The\n\t * higher-level `StoreOptions.compression` (which also accepts an object with\n\t * a level) is normalized down to this string plus `compressionLevel`.\n\t */\n\tcompression?: string;\n\t/**\n\t * Compression level forwarded to RocksDB's `compression_opts.level`. Meaning\n\t * is algorithm-specific; omit to use the algorithm's default.\n\t */\n\tcompressionLevel?: number;\n\t/**\n\t * Apply `compression` to every column family the underlying `DB::Open` opens, rather than\n\t * only the one named by `name`. Requires an explicit `compression`.\n\t */\n\tcompressionForAllColumnFamilies?: boolean;\n\tdbWriteBufferSize?: number;\n\tdisableWAL?: boolean;\n\tenableStats?: boolean;\n\tmaxOpenFiles?: number;\n\tmaxWriteBufferNumber?: number;\n\tmaxWriteBufferSizeToMaintain?: number;\n\tmode?: NativeDatabaseMode;\n\tname?: string;\n\tnoBlockCache?: boolean;\n\tparallelismThreads?: number;\n\treadOnly?: boolean;\n\tstatsLevel?: (typeof stats.StatsLevel)[keyof typeof stats.StatsLevel];\n\ttransactionLogMaxAgeThreshold?: number;\n\ttransactionLogMaxSize?: number;\n\ttransactionLogRetentionMs?: number;\n\ttransactionLogsPath?: string;\n\t/**\n\t * When true, transaction writes to this column family invalidate the\n\t * VerificationTable slot for each written key at write time (not at\n\t * commit time). Enable only for column families whose records are\n\t * cached (e.g. the primary CF of a table). Default: false.\n\t */\n\tverificationTable?: boolean;\n\twriteBufferSize?: number;\n};\n\ntype ResolveCallback<T> = (value: T) => void;\ntype RejectCallback = (err: Error) => void;\n\nexport type UserSharedBufferCallback = () => void;\n\nexport type PurgeLogsOptions = {\n\tbefore?: number;\n\tdestroy?: boolean;\n\t/**\n\t * When `true`, count the entries in each purged log file (extra work) and\n\t * return `PurgedLog[]` instead of the default `string[]` of file paths.\n\t */\n\tincludeEntryCounts?: boolean;\n\tname?: string;\n};\n\n/**\n * A purged transaction log file and the number of entries it held, returned by\n * `purgeLogs()` when `includeEntryCounts` is `true`.\n */\nexport type PurgedLog = { path: string; entries: number };\n\nexport type NativeDatabase = {\n\tnew (): NativeDatabase;\n\taddListener(event: string, callback: (...args: any[]) => void): void;\n\tbackup(\n\t\tresolve: ResolveCallback<number>,\n\t\treject: RejectCallback,\n\t\tbackupDir: string,\n\t\toptions?: BackupOptions\n\t): void;\n\t// `emit` is invoked once per file header (kind 0: name, size, mtime) and once\n\t// per payload chunk (kind 1: Buffer). It must return a promise; native awaits\n\t// it before producing the next event (backpressure), and a rejection aborts.\n\tbackupStream(\n\t\tresolve: ResolveCallback<void>,\n\t\treject: RejectCallback,\n\t\temit: (kind: number, data: string | Uint8Array, size: number, mtime: number) => Promise<void>,\n\t\toptions?: { flushBeforeBackup?: boolean; transactionLogs?: boolean }\n\t): void;\n\tclear(resolve: ResolveCallback<void>, reject: RejectCallback): void;\n\tclearSync(): void;\n\tclose(): void;\n\tcompact(\n\t\tresolve: ResolveCallback<void>,\n\t\treject: RejectCallback,\n\t\tstart?: Key,\n\t\tend?: Key,\n\t\tbottommost?: boolean\n\t): void;\n\tcompactSync(start?: Key, end?: Key, bottommost?: boolean): void;\n\tcolumns: string[];\n\tcreateCheckpoint(\n\t\tresolve: ResolveCallback<void>,\n\t\treject: RejectCallback,\n\t\ttargetPath: string\n\t): void;\n\tdestroy(): void;\n\tdrop(resolve: ResolveCallback<void>, reject: RejectCallback): void;\n\tdropSync(): void;\n\tflush(resolve: ResolveCallback<void>, reject: RejectCallback): void;\n\tflushSync(): void;\n\tnotify(event: string | BufferWithDataView, args?: any[]): boolean;\n\t// Note that keyLengthOrKeyBuffer can be the length of the key if it was written into the shared buffer, or a direct buffer\n\tget(\n\t\tkeyLengthOrKeyBuffer: number | Buffer,\n\t\tresolve: ResolveCallback<Buffer | number>,\n\t\treject: RejectCallback,\n\t\ttxnId?: number,\n\t\texpectedVersion?: number\n\t): number;\n\tgetCompression(): { algorithm: string; level?: number };\n\tgetCount(options?: RangeOptions, txnId?: number): number;\n\tgetDBIntProperty(propertyName: string): number | undefined;\n\tgetDBProperty(propertyName: string): string | undefined;\n\tgetMonotonicTimestamp(): number;\n\tgetOldestSnapshotTimestamp(): number;\n\tgetStat(statName: string): number | StatsHistogramData;\n\tgetStats(all?: false): StatsDefault;\n\tgetStats(all: true): StatsAll;\n\tgetSync(\n\t\tkeyLengthOrKeyBuffer: number | Buffer,\n\t\tflags: number,\n\t\ttxnId?: number,\n\t\texpectedVersion?: number\n\t): Buffer;\n\tgetUserSharedBuffer(\n\t\tkey: BufferWithDataView,\n\t\tdefaultBuffer: ArrayBuffer,\n\t\tcallback?: UserSharedBufferCallback\n\t): ArrayBuffer;\n\thasLock(key: BufferWithDataView): boolean;\n\tlisteners(event: string | BufferWithDataView): number;\n\tlistLogs(): string[];\n\topened: boolean;\n\topen(path: string, options?: NativeDatabaseOptions): void;\n\tpopulateVersion(keyLengthOrKeyBuffer: number | Buffer, version: number): void;\n\tpurgeLogs(options: PurgeLogsOptions & { includeEntryCounts: true }): PurgedLog[];\n\tpurgeLogs(options?: PurgeLogsOptions & { includeEntryCounts?: false }): string[];\n\tpurgeLogs(options?: PurgeLogsOptions): string[] | PurgedLog[];\n\tputSync(key: BufferWithDataView, value: any, txnId?: number): void;\n\tremoveListener(event: string | BufferWithDataView, callback: () => void): boolean;\n\tremoveSync(key: BufferWithDataView, txnId?: number): void;\n\t// Provide a buffer that is used as the default/shared buffer for keys, where functions that provide a key can do so by assigning the key to the shared buffer and providing the length.\n\t// A null value will reset the buffer.\n\tsetDefaultKeyBuffer(buffer: Buffer | Uint8Array | null): void;\n\t// Provide a buffer that is used as the default/shared buffer for value, where functions that use or return a value can do so by assigning the value to the shared buffer and providing/returning the length.\n\t// A null value will reset the buffer.\n\tsetDefaultValueBuffer(buffer: Buffer | Uint8Array | null): void;\n\t// Provide a Uint32Array(2)-backed buffer used by iterators to communicate\n\t// the key length (index 0) and value length (index 1) of each iteration\n\t// step without per-iteration NAPI property accesses.\n\tsetIteratorState(buffer: Buffer | Uint8Array): void;\n\ttryLock(key: BufferWithDataView, callback?: () => void): boolean;\n\tunlock(key: BufferWithDataView): void;\n\tuseLog(name: string): TransactionLog;\n\tverifyVersion(keyLengthOrKeyBuffer: number | Buffer, version: number): boolean;\n\twithLock(key: BufferWithDataView, callback: () => void | Promise<void>): Promise<void>;\n};\n\nexport type RocksDatabaseConfig = {\n\tblockCacheSize?: number;\n\t/**\n\t * Number of slots in the process-global verification table. Each slot is\n\t * 8 bytes; the default of 128K slots is 1 MB. Set to 0 to disable.\n\t *\n\t * Must be configured before the first database is opened. Once the table\n\t * is materialized, attempts to change this value will throw.\n\t */\n\tverificationTableEntries?: number;\n\tcompactOnClose?: boolean;\n\t/**\n\t * Total memtable memory limit (bytes) shared across every database opened\n\t * in this process. When set, RocksDB uses a single `WriteBufferManager` so\n\t * write buffers are bounded process-wide rather than per database. 0 (the\n\t * default) disables the manager.\n\t *\n\t * Can be updated at runtime; the new size takes effect on the existing\n\t * manager via `SetBufferSize`.\n\t */\n\twriteBufferManagerSize?: number;\n\t/**\n\t * When `true`, memtable memory is \"charged\" against the shared block cache\n\t * so the block cache and write buffers draw from a single pool. During\n\t * write bursts the cache shrinks to make room for memtables; once\n\t * memtables flush, the cache can grow back into the reclaimed space.\n\t *\n\t * Has no effect when the block cache is disabled (size 0) or\n\t * `writeBufferManagerSize` is 0. Must be set on the same `config()` call\n\t * that first enables the manager — changing it after the manager has been\n\t * created has no effect on the running instance.\n\t *\n\t * @default false\n\t */\n\twriteBufferManagerCostToCache?: boolean;\n\t/**\n\t * When `true`, writes are stalled once the manager's `buffer_size` is\n\t * exceeded, providing a hard cap on memtable memory. When `false`,\n\t * memtables are allowed to grow past the limit and flushes are simply\n\t * scheduled more aggressively. Off by default to favor write throughput\n\t * over hard memory bounding.\n\t *\n\t * @default false\n\t */\n\twriteBufferManagerAllowStall?: boolean;\n};\n\nconst nativeExtRE = /\\.node$/;\nconst req = createRequire(import.meta.url);\n\n/**\n * Locates the native binding in the `build` directory, then the `prebuilds`\n * directory.\n *\n * @returns The path to the native binding.\n */\nfunction locateBinding(): string {\n\tconst baseDir = dirname(dirname(fileURLToPath(import.meta.url)));\n\n\t// check build directory\n\tfor (const type of ['Release', 'Debug'] as const) {\n\t\ttry {\n\t\t\tconst dir = join(baseDir, 'build', type);\n\t\t\tconst files = readdirSync(dir);\n\t\t\tfor (const file of files) {\n\t\t\t\tif (nativeExtRE.test(file)) {\n\t\t\t\t\treturn resolve(dir, file);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* v8 ignore next -- @preserve */\n\t\t} catch {}\n\t}\n\n\t// determine the Linux C runtime\n\tlet runtime = '';\n\tif (process.platform === 'linux') {\n\t\tlet isMusl = false;\n\t\ttry {\n\t\t\tisMusl = readFileSync('/usr/bin/ldd', 'utf8').includes('musl');\n\t\t} catch {\n\t\t\t// `/usr/bin/ldd` likely doesn't exist\n\t\t\tif (typeof process.report?.getReport === 'function') {\n\t\t\t\tprocess.report.excludeEnv = true;\n\t\t\t\tconst report = process.report.getReport() as unknown as {\n\t\t\t\t\theader?: { glibcVersionRuntime?: string };\n\t\t\t\t\tsharedObjects?: string[];\n\t\t\t\t};\n\t\t\t\tisMusl =\n\t\t\t\t\t(!report?.header || !report.header.glibcVersionRuntime) &&\n\t\t\t\t\tArray.isArray(report?.sharedObjects) &&\n\t\t\t\t\treport.sharedObjects.some(\n\t\t\t\t\t\t(obj) => obj.includes('libc.musl-') || obj.includes('ld-musl-')\n\t\t\t\t\t);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tisMusl =\n\t\t\t\t\tisMusl ||\n\t\t\t\t\texecSync('ldd --version', {\n\t\t\t\t\t\tencoding: 'utf8',\n\t\t\t\t\t\tstdio: 'pipe',\n\t\t\t\t\t}).includes('musl');\n\t\t\t} catch {\n\t\t\t\t// ldd may not exist on some systems such as Docker Hardened Images\n\t\t\t}\n\t\t}\n\t\truntime = isMusl ? '-musl' : '-glibc';\n\t}\n\n\t// the following lines are non-trivial to test, so we'll ignore them\n\t/* v8 ignore next 10 -- @preserve */\n\n\t// check node_modules\n\ttry {\n\t\treturn require.resolve(`@harperfast/rocksdb-js-${process.platform}-${process.arch}${runtime}`);\n\t} catch {}\n\n\tthrow new Error('Unable to locate rocksdb-js native binding');\n}\n\nexport type RegistryStatusDB = {\n\tpath: string;\n\trefCount: number;\n\tcolumnFamilies: string[];\n\ttransactions: number;\n\tclosables: number;\n\tlocks: number;\n\tuserSharedBuffers: number;\n\tlistenerCallbacks: number;\n};\n\nexport type RegistryStatus = RegistryStatusDB[];\n\nconst bindingPath = locateBinding();\n// console.log(`Loading binding from ${bindingPath}`);\nconst binding = req(bindingPath);\n\nexport const config: (options: RocksDatabaseConfig) => void = binding.config;\nexport const FRESH_VERSION_FLAG: number = binding.constants.FRESH_VERSION_FLAG;\nexport const addGlobalListener: (event: string, callback: (...args: any[]) => void) => void =\n\tbinding.addListener;\nexport const removeGlobalListener: (event: string, callback: (...args: any[]) => void) => boolean =\n\tbinding.removeListener;\nexport const globalListenerCount: (event: string) => number = binding.listenerCount;\nexport const globalNotify: (event: string, args?: any[]) => boolean = binding.notify;\nexport const constants: {\n\tALWAYS_CREATE_NEW_BUFFER_FLAG: number;\n\tNOT_IN_MEMORY_CACHE_FLAG: number;\n\tONLY_IF_IN_MEMORY_CACHE_FLAG: number;\n\tPOPULATE_VERSION_FLAG: number;\n\tFRESH_VERSION_FLAG: number;\n\t/**\n\t * Sentinel value resolved (not rejected) by `commit()` when\n\t * `coordinatedRetry: true` and the transaction encountered an IsBusy\n\t * conflict. JS should retry the transaction body immediately.\n\t */\n\tRETRY_NOW_VALUE: number;\n\tTRANSACTION_LOG_TOKEN: number;\n\tTRANSACTION_LOG_ENTRY_HEADER_SIZE: number;\n\tTRANSACTION_LOG_FILE_HEADER_SIZE: number;\n\tITERATOR_REVERSE_FLAG: number;\n\tITERATOR_INCLUSIVE_END_FLAG: number;\n\tITERATOR_EXCLUSIVE_START_FLAG: number;\n\tITERATOR_INCLUDE_VALUES_FLAG: number;\n\tITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG: number;\n\tITERATOR_CONTEXT_IS_TRANSACTION_FLAG: number;\n\tITERATOR_RESULT_DONE: number;\n\tITERATOR_RESULT_FAST: number;\n} = binding.constants;\n/**\n * The friendly names of every compression algorithm compiled into the loaded\n * RocksDB native binding, e.g. `['none', 'snappy', 'lz4', 'zstd']`. The set is\n * fixed for a given binary (it depends on which compression libraries RocksDB\n * was linked against), so this is a static list. `'none'` (no compression) is\n * always present. Use it to validate a `compression` option or to pick an\n * algorithm that is actually available at runtime.\n */\nexport const supportedCompression: readonly string[] = Object.freeze(\n\tbinding.supportedCompression as string[]\n);\nexport const NativeDatabase: NativeDatabase = binding.Database;\nexport const NativeIterator: typeof NativeIteratorCls = binding.Iterator;\nexport const NativeTransaction: NativeTransaction = binding.Transaction;\nexport const TransactionLog: TransactionLog = binding.TransactionLog;\nexport const registryStatus: () => RegistryStatus = binding.registryStatus;\nexport const shutdown: () => void = binding.shutdown;\nexport const currentThreadId: () => number = binding.currentThreadId;\n\n/**\n * Advises the kernel that the file-backed pages of every mapped transaction log\n * are cold (Linux MADV_COLD), so they are reclaimed first under memory pressure\n * without being freed — useful during replication catch-up, where a full read of\n * the logs would otherwise inflate the container's reclaimable cache toward its\n * cgroup limit. No-op on kernels < 5.4, macOS, and Windows.\n *\n * The transaction log registry is a process-global singleton shared across all\n * worker threads, so a single call cools every worker's maps. Call it on an\n * interval from one thread (e.g. an `unref()`ed timer on the main thread).\n *\n * @returns the number of maps cooled and total file-backed bytes advised.\n */\nexport const coolTransactionLogs: () => { maps: number; bytes: number } =\n\tbinding.coolTransactionLogs;\n\n/**\n * Number of live transaction-log memory maps across the process. Internal —\n * used by tests to verify that releasing a frozen log's external buffer unmaps\n * the underlying mapping rather than leaving it retained.\n */\nexport const transactionLogMapCount: () => number = binding.transactionLogMapCount;\n\n/**\n * Test-only: force the next `count` transaction commits to fail with TryAgain (rolled back, so\n * no data is committed), reproducing a stranded-snapshot conflict deterministically. Pass 0 to\n * disarm. Used by the ERR_TRY_AGAIN retry regression test.\n */\nexport const forceTryAgainForTesting: (count: number) => void = binding.forceTryAgainForTesting;\n\n/**\n * Creates a native file lock using the specified file path (`flock` on POSIX,\n * `LockFileEx` on Windows), creating the file and any missing parent\n * directories. Exclusive by default; pass `shared` for a shared (reader) lock\n * that coexists with other shared holders but conflicts with an exclusive\n * holder in either direction. Returns an opaque non-zero token to pass to\n * `fileLockRelease`, or `0` if a conflicting holder — in any process,\n * container, or worker thread — currently has it. Throws on a hard error. The\n * OS handle is owned entirely in native code (no fd crosses into JS), and the\n * kernel releases the lock when the handle closes, including on process death.\n */\nexport const tryFileLock: (file: string, shared?: boolean) => number = binding.tryFileLock;\n\n/**\n * Releases a file lock acquired via `tryFileLock`. A no-op for\n * token `0` or an unknown token.\n */\nexport const fileLockRelease: (token: number) => void = binding.fileLockRelease;\n\n// Module-level backup management functions. These operate on a backup directory\n// and do not require an open database. Wrapped by the `backups` namespace in\n// `backup.ts`; creating a backup is a `RocksDatabase` instance method.\nexport const nativeBackupRestore: (\n\tresolve: ResolveCallback<void>,\n\treject: RejectCallback,\n\tbackupDir: string,\n\tdbDir: string,\n\twalDir: string,\n\toptions?: {\n\t\tbackupId?: number;\n\t\tkeepLogFiles?: boolean;\n\t\tmode?: RestoreOptions['mode'];\n\t}\n) => void = binding.backupRestore;\nexport const nativeBackupList: (\n\tresolve: ResolveCallback<BackupInfo[]>,\n\treject: RejectCallback,\n\tbackupDir: string\n) => void = binding.backupList;\nexport const nativeBackupDelete: (\n\tresolve: ResolveCallback<void>,\n\treject: RejectCallback,\n\tbackupDir: string,\n\tbackupId: number\n) => void = binding.backupDelete;\nexport const nativeBackupPurge: (\n\tresolve: ResolveCallback<void>,\n\treject: RejectCallback,\n\tbackupDir: string,\n\tkeepCount: number\n) => void = binding.backupPurge;\nexport const nativeBackupVerify: (\n\tresolve: ResolveCallback<void>,\n\treject: RejectCallback,\n\tbackupDir: string,\n\tbackupId: number,\n\tverifyWithChecksum: boolean\n) => void = binding.backupVerify;\n\n// Module-level transaction log store validation. Operates on a store directory\n// (a closed database's store or a backup snapshot) and does not require an open\n// database. Wrapped by `validateTransactionLogStore` in\n// `validate-transaction-log.ts`.\nexport const nativeValidateTransactionLog: (\n\tresolve: ResolveCallback<TransactionLogStoreValidation>,\n\treject: RejectCallback,\n\tpath: string,\n\tstrict: boolean\n) => void = binding.validateTransactionLog;\n\nexport const stats: {\n\tStatsLevel: {\n\t\tDisableAll: number;\n\t\tExceptTickers: number;\n\t\tExceptHistogramOrTimers: number;\n\t\tExceptTimers: number;\n\t\tExceptDetailedTimers: number;\n\t\tExceptTimeForMutex: number;\n\t\tAll: number;\n\t};\n} = binding.stats;\n\nexport const version: string = binding.version;\n","import { nativeValidateTransactionLog } from './load-binding.js';\n\n/**\n * The validation result for a single transaction log file within a store, as\n * returned by {@link validateTransactionLogStore}.\n */\nexport interface TransactionLogFileValidation {\n\t/** File name relative to the store directory, e.g. `\"3.txnlog\"`. */\n\tfile: string;\n\t/** Sequence number parsed from the file name. */\n\tsequence: number;\n\t/** On-disk file size in bytes. */\n\tsize: number;\n\t/** Number of well-formed entry frames. */\n\tentries: number;\n\t/** End offset of the validly framed data (header + well-formed entries). */\n\tvalidBytes: number;\n\t/** `true` when `errors` is empty. */\n\tvalid: boolean;\n\t/**\n\t * Conditions that make the file invalid: a bad/missing header, an\n\t * unsupported version, or a mid-file framing break. With `strict`, a torn\n\t * tail is also reported here.\n\t */\n\terrors: string[];\n\t/**\n\t * Conditions that do not invalidate the file: a torn tail (recoverable —\n\t * open-time recovery truncates it without losing committed entries) and\n\t * per-entry anomalies such as suspicious timestamps or undefined flag bits.\n\t */\n\twarnings: string[];\n}\n\n/**\n * The result of validating a transaction log store directory, as returned by\n * {@link validateTransactionLogStore}.\n */\nexport interface TransactionLogStoreValidation {\n\t/** The validated store directory. */\n\tpath: string;\n\t/**\n\t * `true` when there are no store-level errors and every log file is valid.\n\t */\n\tvalid: boolean;\n\t/** Per-file validation results, ordered by sequence number. */\n\tfiles: TransactionLogFileValidation[];\n\t/**\n\t * Store-level errors: malformed file names, an unreadable file, or a\n\t * corrupt `txn.state`.\n\t */\n\terrors: string[];\n\t/**\n\t * Store-level warnings: sequence gaps, unexpected directory entries, or an\n\t * implausible `txn.state` flushed position.\n\t */\n\twarnings: string[];\n}\n\n/**\n * Options for {@link validateTransactionLogStore}.\n */\nexport interface ValidateTransactionLogStoreOptions {\n\t/**\n\t * Report conditions that indicate an incomplete snapshot — a torn tail, a\n\t * sequence gap, or a `txn.state` flushed position beyond the newest log\n\t * file or beyond its file's actual size — as errors instead of warnings. A\n\t * torn tail on a live store is a normal crash artifact that open-time\n\t * recovery truncates, but a backup snapshot captures every surviving file\n\t * on committed entry boundaries and must be clean end to end —\n\t * `backups.verify()` validates snapshots with `strict: true`. Defaults to\n\t * `false`.\n\t */\n\tstrict?: boolean;\n}\n\n/**\n * Validates a transaction log store directory: every `<sequence>.txnlog` file\n * is checked for a valid header (token, version) and intact v1 entry framing\n * (using the same scan as open-time crash recovery), file-name and sequence\n * continuity are checked, and the `txn.state` side file (when present) is\n * checked for shape and a plausible flushed position. The result reports\n * per-file entry counts, errors, and warnings; it does not throw when the\n * store is invalid — check `result.valid`.\n *\n * Runs entirely in native code on a worker thread and does not require (or\n * open) a database, so it works on the store of a closed database and on the\n * per-backup snapshots under `<backupDir>/transaction_logs/<backupId>/` alike.\n *\n * Validating a store that is being actively appended to can spuriously report\n * a torn tail for the current log file — the tail of an in-flight append is\n * indistinguishable from a crash artifact.\n *\n * Rejects if `path` does not exist or is not a directory (a bad argument, as\n * opposed to an invalid store).\n *\n * @param path The store directory, e.g. `<dbDir>/transaction_logs/<name>`.\n * @param options Validation options.\n *\n * @example\n * ```typescript\n * import { validateTransactionLogStore } from '@harperfast/rocksdb-js';\n *\n * const result = await validateTransactionLogStore('/path/to/db/transaction_logs/mylog');\n * if (!result.valid) {\n * for (const file of result.files) {\n * console.error(file.file, file.errors);\n * }\n * }\n * ```\n */\nexport function validateTransactionLogStore(\n\tpath: string,\n\toptions?: ValidateTransactionLogStoreOptions\n): Promise<TransactionLogStoreValidation> {\n\treturn new Promise((resolve, reject) =>\n\t\tnativeValidateTransactionLog(resolve, reject, path, options?.strict ?? false)\n\t);\n}\n","import {\n\tnativeBackupDelete,\n\tnativeBackupList,\n\tfileLockRelease,\n\ttryFileLock,\n\tnativeBackupPurge,\n\tnativeBackupRestore,\n\tnativeBackupVerify,\n} from './load-binding.js';\nimport { validateTransactionLogStore } from './validate-transaction-log.js';\nimport { access, cp, mkdir, readdir, rm } from 'node:fs/promises';\nimport { isAbsolute, join, relative, resolve as resolvePath, sep } from 'node:path';\n\n/** Subdirectory (under a backup directory) holding per-backup transaction log snapshots. */\nconst TRANSACTION_LOGS_DIRNAME = 'transaction_logs';\n\n/** Non-blocking existence check (`fs.existsSync` would block the event loop). */\nasync function exists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Runs `fn` while holding a native file lock for `backupDir`, releasing it when\n * `fn` settles. The lock is exclusive by default — used by the writable-engine\n * operations `backups.delete` and `backups.purge`; backup creation\n * (`Store.backup`) takes the same exclusive lock on the same file natively\n * inside `Database::Backup` (see `runCreateBackup` in\n * `src/binding/database/backup.cpp`), where the backup directory is also\n * created. Throws immediately (without running `fn`) if the backup directory\n * is missing — `tryFileLock` creates missing parents, but `delete`/`purge`/\n * `restore` on a nonexistent directory is a caller error and must not conjure\n * an empty one — or if a conflicting holder has the directory lock.\n *\n * `backups.restore` holds the lock in `shared` mode for its source read:\n * shared holders coexist (concurrent restores are safe), but a writer's\n * exclusive acquisition rejects while a restore is in flight — and vice versa.\n * Without this, a `purge`/`delete` racing a restore can delete the very files\n * the restore is copying, after the restore's default `purgeAllFiles` mode has\n * already wiped the destination — failing the restore with no fallback. A\n * rejected writer, by contrast, just retries later.\n *\n * The remaining read-only operations (`list`, `verify`) use\n * `BackupEngineReadOnly` and are not locked: concurrent readers are safe, and\n * locking them would make cheap listings reject during a long backup. Running\n * them concurrently with a `delete`/`purge` on the same directory is a\n * caller-managed hazard, matching RocksDB's one-writable-engine-per-dir model.\n *\n * RocksDB only serializes work within a single `BackupEngine` instance and has\n * no lock on the backup directory itself. Two writable engines — in any\n * processes — creating/deleting/purging backups in the same directory\n * concurrently race on the per-backup staging directory and both fail,\n * potentially leaving the directory with no usable backup. An in-memory lock\n * cannot prevent this across processes, so the lock lives on disk: a kernel\n * advisory lock (`flock` on POSIX, `LockFileEx` on Windows) held on a\n * `.backup.lock` file at the directory root.\n *\n * The lock is taken entirely in native code (`tryFileLock`), which opens,\n * locks, and later closes the file's OS handle without ever exposing a\n * descriptor to JS — the addon statically links its own C runtime, so a\n * Node/libuv fd is not usable across that boundary. The kernel owning the lock\n * buys two properties a pidfile cannot:\n *\n * - No staleness heuristic. The lock is released when the holder's handle closes\n * — normal release, crash, `kill -9`, container exit — so there is nothing to\n * reclaim and no liveness check.\n * - True cross-context exclusion. The lock conflicts across processes, containers\n * sharing a volume (same kernel), and `worker_threads`.\n *\n * The lock file is never deleted, only locked and unlocked; an unlocked, empty\n * `.backup.lock` at the directory root is the steady state.\n */\nexport async function withBackupDirLock<T>(\n\tbackupDir: string,\n\tfn: () => Promise<T>,\n\toptions?: { shared?: boolean }\n): Promise<T> {\n\tif (!(await exists(backupDir))) {\n\t\tthrow new Error(`Backup directory does not exist: ${backupDir}`);\n\t}\n\tconst token = tryFileLock(join(backupDir, '.backup.lock'), options?.shared === true);\n\tif (token === 0) {\n\t\tthrow new Error(`Backup directory is locked: ${backupDir}`);\n\t}\n\ttry {\n\t\treturn await fn();\n\t} finally {\n\t\tfileLockRelease(token);\n\t}\n}\n\n/**\n * Throws if `backupDir` resolves to the database directory itself or any path\n * beneath it. Backing up into the live database directory would write backup\n * files (the `.backup.lock`, `meta/`, `shared/`, `private/` subtrees) on top of\n * RocksDB's own files, and every subsequent backup would recursively capture\n * the prior ones. Both paths are resolved first so trailing slashes and\n * relative/absolute variants of the same location cannot slip past the check.\n *\n * Only the \"backup dir at or under the database dir\" direction is rejected —\n * the case the user hits by pointing a backup at `<db>` or `<db>/backups`. The\n * reverse (a database nested under the backup dir) is left to the caller: a\n * backup engine writes into named subtrees, not on top of arbitrary sibling\n * files, so it does not clobber the database in place.\n *\n * On case-insensitive filesystems `<db>` and `<db>/../DB/backup` are the same\n * directory on disk, but `relative()` compares case-sensitively and would call\n * the second one \"outside\". We case-fold both paths on the platforms whose\n * default filesystem is case-insensitive (macOS, Windows) so a casing\n * difference cannot slip a backup into the database directory. This is a\n * platform heuristic, not a per-volume probe (a case-sensitive macOS/Windows\n * volume exists), so it can over-reject a legitimately differently-cased\n * sibling there — the safe direction for a guard against clobbering the live\n * database.\n */\nexport function assertBackupDirOutsideDatabase(dbPath: string, backupDir: string): void {\n\tlet resolvedDb = resolvePath(dbPath);\n\tlet resolvedBackup = resolvePath(backupDir);\n\tif (process.platform === 'win32' || process.platform === 'darwin') {\n\t\tresolvedDb = resolvedDb.toLowerCase();\n\t\tresolvedBackup = resolvedBackup.toLowerCase();\n\t}\n\tconst rel = relative(resolvedDb, resolvedBackup);\n\tconst outside = rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel);\n\tif (!outside) {\n\t\tthrow new Error(\n\t\t\t`Backup directory must not be inside the database directory: ${backupDir} is at or within ${dbPath}`\n\t\t);\n\t}\n}\n\n/**\n * Options for creating a backup via `db.backup()`.\n *\n * Backups are whole-database: every column family, the manifest, and (unless\n * `backupLogFiles` is disabled) the write-ahead log are captured. A backup is\n * not scoped to an individual `Store`.\n */\nexport interface BackupOptions {\n\t/**\n\t * Include write-ahead log files in the backup. Defaults to `true`.\n\t */\n\tbackupLogFiles?: boolean;\n\n\t/**\n\t * Preflight the destination volume and reject the backup when it lacks room.\n\t * Defaults to `true`. The rejection is an I/O error whose message reports the\n\t * available and required bytes (it is not distinguishable by an `err.code`).\n\t *\n\t * The required size is estimated conservatively as a *full* copy of the\n\t * database's live files, plus the transaction-log snapshot when\n\t * `transactionLogs` is enabled (a backup only ever copies files, so this can\n\t * never under-estimate the bytes written). For incremental backups to a\n\t * right-sized volume this may over-reject — set `false` to skip the check in\n\t * that case. The check also self-disables when free space is unknowable (e.g.\n\t * some network filesystems report 0), so it never blocks a backup on an\n\t * untrustworthy number.\n\t *\n\t * Only applies to directory-target backups; the streaming backup path is\n\t * unaffected.\n\t */\n\tcheckDiskSpace?: boolean;\n\n\t/**\n\t * Flush the memtable before backing up. Defaults to `true` when the database\n\t * was opened with `disableWAL` (otherwise unflushed data would be lost from\n\t * the backup), and `false` otherwise.\n\t */\n\tflushBeforeBackup?: boolean;\n\n\t/**\n\t * Number of background threads used to copy files. Defaults to `1`.\n\t */\n\tmaxBackgroundOperations?: number;\n\n\t/**\n\t * Arbitrary application metadata stored with the backup and returned by\n\t * `backups.list()`.\n\t */\n\tmetadata?: string;\n\n\t/**\n\t * Distinguish shared files by checksum to avoid collisions across databases.\n\t * Defaults to `true`. Only relevant when `shareTableFiles` is enabled.\n\t */\n\tshareFilesWithChecksum?: boolean;\n\n\t/**\n\t * Share table/blob files between backups in the same directory to enable\n\t * incremental backups. Defaults to `true`.\n\t */\n\tshareTableFiles?: boolean;\n\n\t/**\n\t * `fsync` backup files — including the transaction log snapshot when\n\t * `transactionLogs` is enabled — for crash consistency. Defaults to `true`.\n\t */\n\tsync?: boolean;\n\n\t/**\n\t * Snapshot the transaction log store into\n\t * `<backupDir>/transaction_logs/<backupId>/`. Defaults to `false`. This is an\n\t * all-or-nothing snapshot per backup (not incremental); `backups.delete()` and\n\t * `backups.purge()` remove the corresponding log snapshots, and\n\t * `backups.restore()` restores them into the database directory.\n\t *\n\t * The snapshot is staged and atomically renamed into place after every file\n\t * is copied (and fsynced, per `sync`), so a crash mid-backup can never leave\n\t * a partial snapshot: a backup id either has its complete log snapshot or\n\t * none at all.\n\t *\n\t * The log snapshot is captured just after the RocksDB engine snapshot, so it\n\t * may include entries committed between the two — the restored logs can run\n\t * slightly ahead of the restored key-value data, never behind it. That bias\n\t * is safe for redo-style logs that are replayed against the restored data.\n\t */\n\ttransactionLogs?: boolean;\n}\n\n/**\n * The level of incremental restore to perform.\n *\n * - `purgeAllFiles` (default): purge the destination directory and restore all\n * files from the backup. Destructive but always correct.\n * - `keepLatestDbSessionIdFiles`: efficiently restore a healthy database,\n * reusing existing files that match the backup.\n * - `verifyChecksum`: reuse existing destination files whose checksums match the\n * backup, replacing only mismatched/corrupt files.\n */\nexport type RestoreMode = 'purgeAllFiles' | 'keepLatestDbSessionIdFiles' | 'verifyChecksum';\n\n/**\n * Options for restoring a backup via `backups.restore()`.\n */\nexport interface RestoreOptions {\n\t/**\n\t * The backup id to restore. Defaults to the latest non-corrupt backup.\n\t */\n\tbackupId?: number;\n\n\t/**\n\t * Directory to restore write-ahead log files into. Defaults to the database\n\t * directory.\n\t */\n\twalDir?: string;\n\n\t/**\n\t * Keep existing log files in `walDir` rather than overwriting them. Defaults\n\t * to `false`.\n\t */\n\tkeepLogFiles?: boolean;\n\n\t/**\n\t * The restore strategy. Defaults to `purgeAllFiles`, which is destructive.\n\t */\n\tmode?: RestoreMode;\n}\n\n/**\n * Information about a single backup, as returned by `backups.list()`.\n */\nexport interface BackupInfo {\n\t/** The backup id (monotonically increasing integer). */\n\tbackupId: number;\n\t/** Creation time in seconds since the epoch. */\n\ttimestamp: number;\n\t/** Total size in bytes of the backed-up file payloads. */\n\tsize: number;\n\t/** Number of files in the backup (some may be shared with other backups). */\n\tnumberFiles: number;\n\t/** Application metadata supplied when the backup was created. */\n\tappMetadata: string;\n}\n\n/**\n * Removes `<backupDir>/transaction_logs/<id>` subtrees whose backup id no longer\n * corresponds to a surviving backup. Called after a `purge` (which holds the\n * backup-dir lock); a no-op when no transaction logs were backed up. Self-healing:\n * it drops every log subtree without a live backup. Note the surviving set comes\n * from `nativeBackupList`, which omits corrupt backups — a still-present but\n * corrupt backup's logs may be pruned (acceptable: it cannot be restored anyway).\n * This also sweeps `.staging-*` leftovers from a crashed backup process (a\n * staging name never matches a live backup id); backup creation sweeps them\n * natively as well, under the backup-dir lock.\n */\nasync function pruneOrphanedTransactionLogs(backupDir: string): Promise<void> {\n\tconst logsRoot = join(backupDir, TRANSACTION_LOGS_DIRNAME);\n\tlet ids: string[];\n\ttry {\n\t\tids = await readdir(logsRoot);\n\t} catch (err) {\n\t\tif ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\treturn; // no transaction logs were backed up\n\t\t}\n\t\tthrow err;\n\t}\n\n\tconst list = await new Promise<BackupInfo[]>((resolve, reject) =>\n\t\tnativeBackupList(resolve, reject, backupDir)\n\t);\n\tconst surviving = new Set(list.map((info) => String(info.backupId)));\n\n\tawait Promise.all(\n\t\tids\n\t\t\t.filter((id) => !surviving.has(id))\n\t\t\t.map((id) => rm(join(logsRoot, id), { recursive: true, force: true }))\n\t);\n}\n\n/**\n * Restores the transaction log snapshot for the restored backup into\n * `<dbDir>/transaction_logs/`, wiping the destination first so that restoring an\n * older backup over a newer one cannot leave stale (newer) log files behind.\n *\n * Only acts when THIS backup actually captured logs: if the restored id has no\n * snapshot, the destination is left untouched. Wiping unconditionally would\n * destroy on-disk logs that a mixed-mode (`transactionLogs:false`) backup never\n * managed.\n *\n * Offline only: the files are picked up when the database is next opened. mtimes\n * are preserved because the store derives file age (rotation/retention) from\n * mtime — a fresh mtime would break retention.\n */\nasync function restoreTransactionLogs(\n\tbackupDir: string,\n\tdbDir: string,\n\tbackupId?: number\n): Promise<void> {\n\tconst logsRoot = join(backupDir, TRANSACTION_LOGS_DIRNAME);\n\tif (!(await exists(logsRoot))) {\n\t\treturn; // this backup directory has no transaction log snapshots\n\t}\n\n\t// Resolve the restored backup id (the latest, when unspecified).\n\tlet id = backupId;\n\tif (id === undefined) {\n\t\tconst list = await new Promise<BackupInfo[]>((resolve, reject) =>\n\t\t\tnativeBackupList(resolve, reject, backupDir)\n\t\t);\n\t\tif (list.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tid = Math.max(...list.map((info) => info.backupId));\n\t}\n\n\tconst logsSrc = join(logsRoot, String(id));\n\tif (!(await exists(logsSrc))) {\n\t\t// The restored backup captured no logs — do not touch the destination's\n\t\t// existing transaction logs.\n\t\treturn;\n\t}\n\n\t// This backup has logs: wipe the destination, then restore its snapshot.\n\tconst logsDest = join(dbDir, TRANSACTION_LOGS_DIRNAME);\n\tawait rm(logsDest, { recursive: true, force: true });\n\tawait cp(logsSrc, logsDest, { recursive: true, preserveTimestamps: true });\n}\n\n/**\n * Backup management operations that act on a backup directory and do not\n * require an open database. To create a backup, use the `db.backup()` instance\n * method instead (it needs a live database for a consistent snapshot).\n *\n * @example\n * ```typescript\n * import { backups } from '@harperfast/rocksdb-js';\n *\n * const id = await db.backup('/path/to/backups');\n * db.close();\n * await backups.restore('/path/to/backups', '/path/to/restored-db');\n * ```\n */\nexport const backups = {\n\t/**\n\t * Restores a database from a backup directory into a (closed) database\n\t * directory. The default mode purges the destination directory, so it must\n\t * not point at a live database.\n\t *\n\t * Holds the backup directory lock in shared mode for the duration: multiple\n\t * restores can read concurrently, but a writer (`db.backup()`, `delete`,\n\t * `purge`) rejects while a restore is in flight rather than deleting files\n\t * out from under it — and a restore rejects while a writer holds the lock.\n\t *\n\t * The shared lock needs no write access to `backupDir`, so restoring from a\n\t * read-only backup directory (immutable/WORM store, read-only-mounted volume)\n\t * works: the lock is taken on an existing `.backup.lock` read-only, degrading\n\t * to a no-op only when the media is read-only for every process (`EROFS`). A\n\t * mere permission denial hard-fails instead — it doesn't prove a privileged\n\t * writer isn't running.\n\t */\n\tasync restore(backupDir: string, dbDir: string, options?: RestoreOptions): Promise<void> {\n\t\t// Normalize before comparing so trailing slashes or relative/absolute\n\t\t// variants of the same directory can't slip past the guard and let a\n\t\t// destructive restore purge the backup directory itself.\n\t\tif (resolvePath(backupDir) === resolvePath(dbDir)) {\n\t\t\tthrow new Error('Backup directory and database directory must be different');\n\t\t}\n\n\t\treturn withBackupDirLock(\n\t\t\tbackupDir,\n\t\t\tasync () => {\n\t\t\t\tconst walDir = options?.walDir ?? dbDir;\n\t\t\t\tawait mkdir(dbDir, { recursive: true });\n\t\t\t\tif (walDir !== dbDir) {\n\t\t\t\t\tawait mkdir(walDir, { recursive: true });\n\t\t\t\t}\n\n\t\t\t\tawait new Promise<void>((resolve, reject) =>\n\t\t\t\t\tnativeBackupRestore(resolve, reject, backupDir, dbDir, walDir, {\n\t\t\t\t\t\tbackupId: options?.backupId,\n\t\t\t\t\t\tkeepLogFiles: options?.keepLogFiles,\n\t\t\t\t\t\tmode: options?.mode,\n\t\t\t\t\t})\n\t\t\t\t);\n\n\t\t\t\t// Restore the transaction log snapshot (if this backup included one). Wipes\n\t\t\t\t// the destination first so an older restore leaves no newer log stragglers.\n\t\t\t\tawait restoreTransactionLogs(backupDir, dbDir, options?.backupId);\n\t\t\t},\n\t\t\t{ shared: true }\n\t\t);\n\t},\n\n\t/**\n\t * Lists the non-corrupt backups in a backup directory, ordered by id.\n\t */\n\tlist(backupDir: string): Promise<BackupInfo[]> {\n\t\treturn new Promise((resolve, reject) => nativeBackupList(resolve, reject, backupDir));\n\t},\n\n\t/**\n\t * Deletes a specific backup. Shared files are reference-counted and only\n\t * removed once no remaining backup references them.\n\t */\n\tasync delete(backupDir: string, backupId: number): Promise<void> {\n\t\treturn withBackupDirLock(backupDir, async () => {\n\t\t\tawait new Promise<void>((resolve, reject) =>\n\t\t\t\tnativeBackupDelete(resolve, reject, backupDir, backupId)\n\t\t\t);\n\t\t\t// Remove only this backup's own log snapshot: precise (no dependence on\n\t\t\t// the backup listing, which omits corrupt backups) and best-effort (the\n\t\t\t// backup is already gone, so a cleanup failure must not fail the delete).\n\t\t\ttry {\n\t\t\t\tawait rm(join(backupDir, TRANSACTION_LOGS_DIRNAME, String(backupId)), {\n\t\t\t\t\trecursive: true,\n\t\t\t\t\tforce: true,\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t// Best-effort: at worst an orphaned subtree remains for a later purge.\n\t\t\t}\n\t\t});\n\t},\n\n\t/**\n\t * Deletes all but the newest `keepCount` backups.\n\t */\n\tasync purge(backupDir: string, keepCount: number): Promise<void> {\n\t\treturn withBackupDirLock(backupDir, async () => {\n\t\t\tawait new Promise<void>((resolve, reject) =>\n\t\t\t\tnativeBackupPurge(resolve, reject, backupDir, keepCount)\n\t\t\t);\n\t\t\t// Best-effort: the backups are already purged, so a log-cleanup failure\n\t\t\t// must not fail the purge.\n\t\t\ttry {\n\t\t\t\tawait pruneOrphanedTransactionLogs(backupDir);\n\t\t\t} catch {\n\t\t\t\t// Best-effort orphan cleanup.\n\t\t\t}\n\t\t});\n\t},\n\n\t/**\n\t * Verifies a backup's file sizes, and optionally their checksums (which\n\t * requires reading all backed-up data).\n\t *\n\t * When the backup was created with `transactionLogs: true`, the backup's\n\t * transaction log snapshot (`<backupDir>/transaction_logs/<backupId>/`) is\n\t * also validated — every log file's header and entry framing must be intact\n\t * (snapshots are copied on committed entry boundaries, so even a torn tail\n\t * is a verification failure). Set `verifyTransactionLogs: false` to skip.\n\t */\n\tasync verify(\n\t\tbackupDir: string,\n\t\tbackupId: number,\n\t\toptions?: { verifyWithChecksum?: boolean; verifyTransactionLogs?: boolean }\n\t): Promise<void> {\n\t\tawait new Promise<void>((resolve, reject) =>\n\t\t\tnativeBackupVerify(resolve, reject, backupDir, backupId, options?.verifyWithChecksum ?? false)\n\t\t);\n\n\t\tif (options?.verifyTransactionLogs === false) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst logsDir = join(backupDir, TRANSACTION_LOGS_DIRNAME, String(backupId));\n\t\tif (!(await exists(logsDir))) {\n\t\t\t// this backup captured no transaction logs\n\t\t\treturn;\n\t\t}\n\n\t\tconst failures: string[] = [];\n\t\tfor (const entry of await readdir(logsDir, { withFileTypes: true })) {\n\t\t\tif (!entry.isDirectory()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result = await validateTransactionLogStore(join(logsDir, entry.name), {\n\t\t\t\tstrict: true,\n\t\t\t});\n\t\t\tif (!result.valid) {\n\t\t\t\tconst details = [\n\t\t\t\t\t...result.errors,\n\t\t\t\t\t...result.files.flatMap((file) => file.errors.map((error) => `${file.file}: ${error}`)),\n\t\t\t\t];\n\t\t\t\tfailures.push(`${entry.name}: ${details.join('; ')}`);\n\t\t\t}\n\t\t}\n\t\tif (failures.length > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Backup ${backupId} transaction log verification failed: ${failures.join('\\n')}`\n\t\t\t);\n\t\t}\n\t},\n};\n","export type MaybePromise<T> = T | Promise<T>;\n\nexport type MaybePromiseFunction<T> = () => MaybePromise<T>;\n\n/**\n * Parses a duration string into milliseconds.\n *\n * @param duration - The duration string to parse.\n * @returns The duration in milliseconds.\n *\n * @example\n * ```typescript\n * parseDuration('1s'); // 1000\n * parseDuration('1m'); // 60000\n * parseDuration('1h'); // 3600000\n * parseDuration('1d'); // 86400000\n * parseDuration('1ms'); // 1\n * parseDuration('1s 1ms'); // 1001\n * parseDuration('1m 1s'); // 61000\n * parseDuration('foo'); // throws error\n *\n * parseDuration(1000); // 1000\n * parseDuration(60000); // 60000\n * parseDuration(3600000); // 3600000\n * parseDuration(86400000); // 86400000\n * parseDuration(NaN); // throws error\n * ```\n */\nexport function parseDuration(duration: number | string): number {\n\tif (typeof duration === 'number') {\n\t\tif (isNaN(duration) || !isFinite(duration)) {\n\t\t\tthrow new Error(`Invalid duration: ${duration}`);\n\t\t}\n\t\treturn duration;\n\t}\n\n\tlet result = 0;\n\tfor (const part of duration.split(' ')) {\n\t\tconst m = part.match(/^(\\d+)\\s*(ms|s|m|h|d)?$/);\n\t\tif (!m) {\n\t\t\tthrow new Error(`Invalid duration: ${duration}`);\n\t\t}\n\n\t\tconst [, value, unit] = m;\n\t\tlet num = parseInt(value, 10);\n\t\tswitch (unit) {\n\t\t\tcase 's':\n\t\t\t\tnum *= 1000;\n\t\t\t\tbreak;\n\t\t\tcase 'm':\n\t\t\t\tnum *= 1000 * 60;\n\t\t\t\tbreak;\n\t\t\tcase 'h':\n\t\t\t\tnum *= 1000 * 60 * 60;\n\t\t\t\tbreak;\n\t\t\tcase 'd':\n\t\t\t\tnum *= 1000 * 60 * 60 * 24;\n\t\t\t\tbreak;\n\t\t}\n\t\tresult += num;\n\t}\n\treturn result;\n}\n\n/**\n * Helper function handling `MaybePromise` results.\n *\n * If the result originates from a function that could throw an error, wrap it\n * in a function so this function can catch any errors and use a unified error\n * handling mechanism.\n */\nexport function when<T>(\n\tsubject: MaybePromise<T> | MaybePromiseFunction<T>,\n\tcallback?: (value: T) => MaybePromise<T>,\n\terrback?: (reason: any) => T\n): MaybePromise<T> {\n\ttry {\n\t\tlet result: MaybePromise<T>;\n\n\t\tif (typeof subject === 'function') {\n\t\t\tresult = (subject as MaybePromiseFunction<T>)();\n\t\t} else {\n\t\t\tresult = subject;\n\t\t}\n\n\t\tif (result instanceof Promise) {\n\t\t\treturn result.then(callback, errback) as T;\n\t\t}\n\n\t\treturn callback ? callback(result as T) : (result as T);\n\t} catch (error) {\n\t\treturn errback ? errback(error) : Promise.reject(error);\n\t}\n}\n\n/**\n * Polyfill for `Promise.withResolvers`.\n *\n * Note: This can be removed once Node.js 18 and 20 are no longer supported.\n *\n * @returns A tuple of `resolve`, `reject`, and `promise`.\n */\nexport function withResolvers<T>(): {\n\tresolve: (value: T) => void;\n\treject: (reason: any) => void;\n\tpromise: Promise<T>;\n} {\n\tlet resolve, reject;\n\tconst promise = new Promise<T>((res, rej) => {\n\t\tresolve = res;\n\t\treject = rej;\n\t});\n\treturn { resolve, reject, promise };\n}\n","import type { BufferWithDataView, Key } from './encoding.js';\nimport { FRESH_VERSION_FLAG } from './load-binding.js';\nimport type { NativeTransaction, TransactionLog } from './load-binding.js';\nimport type { GetOptions, PutOptions, Store, StoreContext, StoreGetOptions } from './store.js';\nimport type { Transaction } from './transaction.js';\nimport { type MaybePromise, when } from './util.js';\n\nexport interface RocksDBOptions {\n\t/**\n\t * When `true`, RocksDB will do some enhancements for prefetching the data.\n\t * Defaults to `true`. Note that RocksDB defaults this to `false`.\n\t */\n\tadaptiveReadahead?: boolean;\n\n\t/**\n\t * When `true`, RocksDB will prefetch some data async and apply it if reads\n\t * are sequential and its internal automatic prefetching. Defaults to\n\t * `true`. Note that RocksDB defaults this to `false`.\n\t */\n\tasyncIO?: boolean;\n\n\t/**\n\t * When `true`, RocksDB will auto-tune the readahead size during scans\n\t * internally based on the block cache data when block caching is enabled,\n\t * an end key (e.g. upper bound) is set, and prefix is the same as the start\n\t * key. Defaults to `true`.\n\t */\n\tautoReadaheadSize?: boolean;\n\n\t/**\n\t * When `true`, after the iterator is closed, a background job is scheduled\n\t * to flush the job queue and delete obsolete files. Defaults to `true`.\n\t * Note that RocksDB defaults this to `false`.\n\t */\n\tbackgroundPurgeOnIteratorCleanup?: boolean;\n\n\t/**\n\t * When `true`, the iterator will fill the block cache. Filling the block\n\t * cache is not desirable for bulk scans and could impact eviction order.\n\t * Defaults to `false`. Note that RocksDB defaults this to `true`.\n\t */\n\tfillCache?: boolean;\n\n\t/**\n\t * The RocksDB readahead size. RocksDB does auto-readahead for iterators\n\t * when there is more than two reads for a table file. The readahead\n\t * starts at 8KB and doubles on every additional read up to 256KB. This\n\t * option can help if most of the range scans are large and if a larger\n\t * readahead than that enabled by auto-readahead is needed. Using a large\n\t * readahead size (> 2MB) can typically improve the performance of forward\n\t * iteration on spinning disks. Defaults to `0`.\n\t */\n\treadaheadSize?: number;\n\n\t/**\n\t * When `true`, creates a \"tailing iterator\" which is a special iterator\n\t * that has a view of the complete database including newly added data and\n\t * is optimized for sequential reads. This will return records that were\n\t * inserted into the database after the creation of the iterator. Defaults\n\t * to `false`.\n\t */\n\ttailing?: boolean;\n}\n\nexport interface RangeOptions extends RocksDBOptions {\n\t/**\n\t * The range end key, otherwise known as the \"upper bound\". Defaults to\n\t * the last key in the database.\n\t */\n\tend?: Key | Uint8Array;\n\n\t/**\n\t * When `true`, the iterator will exclude the first key if it matches the start key.\n\t * Defaults to `false`.\n\t */\n\texclusiveStart?: boolean;\n\n\t/**\n\t * When `true`, the iterator will include the last key if it matches the end\n\t * key. Defaults to `false`.\n\t */\n\tinclusiveEnd?: boolean;\n\n\t/**\n\t * The range start key, otherwise known as the \"lower bound\". Defaults to\n\t * the first key in the database.\n\t */\n\tstart?: Key | Uint8Array;\n}\n\nexport interface IteratorOptions extends RangeOptions {\n\t// decoder?: (value: any) => any,\n\n\t// exactMatch?: boolean;\n\n\t/**\n\t * The maximum number of entries to yield. When set, iteration stops after\n\t * `limit` entries regardless of the range bounds. Values <= 0 yield nothing.\n\t * Unset means no limit.\n\t */\n\tlimit?: number;\n\n\t/**\n\t * A specific key to match which may result in zero, one, or many values.\n\t */\n\tkey?: Key;\n\n\t// offset?: number;\n\n\t/**\n\t * When `true`, only returns the number of values for the given query.\n\t */\n\tonlyCount?: boolean;\n\n\t/**\n\t * When `true`, the iterator will iterate in reverse order. Defaults to\n\t * `false`.\n\t */\n\treverse?: boolean;\n\n\t// snapshot?: boolean;\n\n\t/**\n\t * When `true`, decodes and returns the value. When `false`, the value is\n\t * omitted. Defaults to `true`.\n\t */\n\tvalues?: boolean;\n\n\t/**\n\t * When `true`, the iterator will only return the values.\n\t */\n\tvaluesOnly?: boolean;\n}\n\nexport interface DBITransactional {\n\ttransaction?: Transaction;\n}\n\n/**\n * The base class for all database operations. This base class is shared by\n * `RocksDatabase` and `Transaction`.\n *\n * This class is not meant to be used directly.\n */\nexport class DBI<T extends DBITransactional | unknown = unknown> {\n\t/**\n\t * The RocksDB context for `get()`, `put()`, and `remove()`.\n\t */\n\t_context: StoreContext;\n\n\t/**\n\t * The database store instance. The store instance is tied to the database\n\t * instance and shared with transaction instances.\n\t */\n\tstore: Store;\n\n\t/**\n\t * Initializes the DBI context.\n\t *\n\t * @param store - The store instance.\n\t * @param transaction - The transaction instance.\n\t */\n\tconstructor(store: Store, transaction?: NativeTransaction) {\n\t\tif (new.target === DBI) {\n\t\t\tthrow new Error('DBI is an abstract class and cannot be instantiated directly');\n\t\t}\n\n\t\t// this ideally should not be public, but JavaScript doesn't support\n\t\t// protected properties\n\t\tthis.store = store;\n\n\t\tthis._context = transaction || store.db;\n\t}\n\n\t/**\n\t * Adds a listener for the given key.\n\t *\n\t * @param event - The event name to add the listener for.\n\t * @param callback - The callback to add.\n\t */\n\taddListener(event: string, callback: (...args: any[]) => void): this {\n\t\tthis.store.db.addListener(event, callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Retrieves the value for the given key, then returns the decoded value.\n\t */\n\tget(key: Key, options?: GetOptions & T): MaybePromise<any | undefined> {\n\t\tif (this.store.decoderCopies) {\n\t\t\treturn when(\n\t\t\t\t() => this.getBinaryFast(key, options),\n\t\t\t\t(result) => {\n\t\t\t\t\tif (result === undefined || result === FRESH_VERSION_FLAG) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (options?.skipDecode) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this.store.decodeValue(result as BufferWithDataView);\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn when(\n\t\t\t() => this.getBinary(key, options),\n\t\t\t(result) =>\n\t\t\t\tresult === undefined || result === FRESH_VERSION_FLAG\n\t\t\t\t\t? result\n\t\t\t\t\t: this.store.encoding === 'binary' || !this.store.decoder || options?.skipDecode\n\t\t\t\t\t\t? result\n\t\t\t\t\t\t: this.store.decodeValue(result as BufferWithDataView)\n\t\t);\n\t}\n\n\t/**\n\t * Retrieves the binary data for the given key. This is just like `get()`,\n\t * but bypasses the decoder.\n\t *\n\t * Note: Used by HDBreplication.\n\t */\n\tgetBinary(key: Key, options?: GetOptions & T): MaybePromise<Buffer | number | undefined> {\n\t\tif (!this.store.isOpen()) {\n\t\t\treturn Promise.reject(new Error('Database not open'));\n\t\t}\n\n\t\treturn this.store.get(this._context, key, true, options as StoreGetOptions);\n\t}\n\n\t/**\n\t * Synchronously retrieves the binary data for the given key.\n\t */\n\tgetBinarySync(key: Key, options?: GetOptions & T): Buffer | number | undefined {\n\t\tif (!this.store.isOpen()) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\treturn this.store.getSync(this._context, key, true, options);\n\t}\n\n\t/**\n\t * Retrieves the binary data for the given key using a preallocated,\n\t * reusable buffer. Data in the buffer is only valid until the next get\n\t * operation (including cursor operations).\n\t *\n\t * Note: The reusable buffer slightly differs from a typical buffer:\n\t * - `.length` is set to the size of the value\n\t * - `.byteLength` is set to the size of the full allocated memory area for\n\t * the buffer (usually much larger).\n\t */\n\tgetBinaryFast(key: Key, options?: GetOptions & T): MaybePromise<Buffer | number | undefined> {\n\t\tif (!this.store.isOpen()) {\n\t\t\treturn Promise.reject(new Error('Database not open'));\n\t\t}\n\n\t\treturn this.store.get(this._context, key, false, options as StoreGetOptions);\n\t}\n\n\t/**\n\t * Synchronously retrieves the binary data for the given key using a\n\t * preallocated, reusable buffer. Data in the buffer is only valid until the\n\t * next get operation (including cursor operations).\n\t */\n\tgetBinaryFastSync(key: Key, options?: GetOptions & T): Buffer | number | undefined {\n\t\tif (!this.store.isOpen()) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\treturn this.store.getSync(this._context, key, false, options);\n\t}\n\n\t/**\n\t * Retrieves all keys within a range.\n\t */\n\tgetKeys(options?: IteratorOptions & T): any | undefined {\n\t\treturn this.store.getKeys(this._context, options);\n\t}\n\n\t/**\n\t * Retrieves the number of keys within a range.\n\t *\n\t * @param options - The range options.\n\t * @returns The number of keys within the range.\n\t *\n\t * @example\n\t * ```typescript\n\t * const total = db.getKeysCount();\n\t * const range = db.getKeysCount({ start: 'a', end: 'z' });\n\t * ```\n\t */\n\tgetKeysCount(options?: RangeOptions & T): number {\n\t\treturn this.store.getKeysCount(this._context, options);\n\t}\n\n\t/**\n\t * Retrieves a range of keys and their values.\n\t *\n\t * @param options - The iterator options.\n\t * @returns A range iterable.\n\t *\n\t * @example\n\t * ```typescript\n\t * for (const { key, value } of db.getRange()) {\n\t * console.log({ key, value });\n\t * }\n\t *\n\t * for (const { key, value } of db.getRange({ start: 'a', end: 'z' })) {\n\t * console.log({ key, value });\n\t * }\n\t * ```\n\t */\n\tgetRange(options?: IteratorOptions & T): any | undefined {\n\t\treturn this.store.getRange(this._context, options);\n\t}\n\n\t/**\n\t * Synchronously retrieves the value for the given key, then returns the\n\t * decoded value.\n\t */\n\tgetSync(key: Key, options?: GetOptions & T): any | undefined {\n\t\tif (this.store.decoderCopies) {\n\t\t\tconst bytes = this.getBinaryFastSync(key, options);\n\t\t\treturn bytes === undefined || bytes === FRESH_VERSION_FLAG\n\t\t\t\t? bytes\n\t\t\t\t: this.store.decodeValue(bytes as BufferWithDataView);\n\t\t}\n\n\t\tif (this.store.encoding === 'binary') {\n\t\t\treturn this.getBinarySync(key, options);\n\t\t}\n\n\t\tif (this.store.decoder) {\n\t\t\tconst result = this.getBinarySync(key, options);\n\t\t\treturn !result || result === FRESH_VERSION_FLAG\n\t\t\t\t? result\n\t\t\t\t: this.store.decodeValue(result as BufferWithDataView);\n\t\t}\n\n\t\tif (!this.store.isOpen()) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\treturn this.store.decodeValue(this.store.getSync(this._context, key, true, options));\n\t}\n\n\t/**\n\t * Gets the number of listeners for the given key.\n\t *\n\t * @param event - The event name to get the listeners for.\n\t * @returns The number of listeners for the given key.\n\t */\n\tlisteners(event: string | BufferWithDataView): number {\n\t\treturn this.store.db.listeners(event);\n\t}\n\n\t/**\n\t * Notifies an event for the given key.\n\t *\n\t * @param event - The event name to emit the event for.\n\t * @param args - The arguments to emit.\n\t * @returns `true` if there were listeners, `false` otherwise.\n\t */\n\tnotify(event: string, ...args: any[]): boolean {\n\t\treturn this.store.db.notify(event, args);\n\t}\n\n\t/**\n\t * Alias for `removeListener()`.\n\t *\n\t * @param event - The event name to remove the listener for.\n\t * @param callback - The callback to remove.\n\t */\n\toff(event: string, callback: (...args: any[]) => void): this {\n\t\tthis.store.db.removeListener(event, callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Alias for `addListener()`.\n\t *\n\t * @param event - The event name to add the listener for.\n\t * @param callback - The callback to add.\n\t */\n\ton(event: string, callback: (...args: any[]) => void): this {\n\t\tthis.store.db.addListener(event, callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a one-time listener, then automatically removes it.\n\t *\n\t * @param event - The event name to add the listener for.\n\t * @param callback - The callback to add.\n\t */\n\tonce(event: string, callback: (...args: any[]) => void): this {\n\t\tconst wrapper = (...args: any[]) => {\n\t\t\tthis.removeListener(event, wrapper);\n\t\t\tcallback(...args);\n\t\t};\n\t\tthis.store.db.addListener(event, wrapper);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stores a value for the given key.\n\t *\n\t * @param key - The key to store the value for.\n\t * @param value - The value to store.\n\t * @param options - The put options.\n\t * @returns The key and value.\n\t *\n\t * @example\n\t * ```typescript\n\t * await db.put('a', 'b');\n\t * ```\n\t */\n\tasync put(key: Key, value: any, options?: PutOptions & T): Promise<void> {\n\t\treturn this.store.putSync(this._context, key, value, options);\n\t}\n\n\t/**\n\t * Synchronously stores a value for the given key.\n\t *\n\t * @param key - The key to store the value for.\n\t * @param value - The value to store.\n\t * @param options - The put options.\n\t * @returns The key and value.\n\t *\n\t * @example\n\t * ```typescript\n\t * db.putSync('a', 'b');\n\t * ```\n\t */\n\tputSync(key: Key, value: any, options?: PutOptions & T): void {\n\t\treturn this.store.putSync(this._context, key, value, options);\n\t}\n\n\t/**\n\t * Removes a value for the given key. If the key does not exist, it will\n\t * not error.\n\t *\n\t * @param key - The key to remove the value for.\n\t * @param options - The remove options.\n\t * @returns The key and value.\n\t *\n\t * @example\n\t * ```typescript\n\t * await db.remove('a');\n\t * ```\n\t */\n\tasync remove(key: Key, options?: T): Promise<void> {\n\t\treturn this.store.removeSync(this._context, key, options);\n\t}\n\n\t/**\n\t * Removes a value for the given key. If the key does not exist, it will\n\t * not error.\n\t *\n\t * @param key - The key to remove the value for.\n\t * @param options - The remove options.\n\t * @returns The key and value.\n\t *\n\t * @example\n\t * ```typescript\n\t * db.removeSync('a');\n\t * ```\n\t */\n\tremoveSync(key: Key, options?: T): void {\n\t\treturn this.store.removeSync(this._context, key, options);\n\t}\n\n\t/**\n\t * Removes an event listener. You must specify the exact same callback that was\n\t * used in `addListener()`.\n\t *\n\t * @param event - The event name to remove the listener for.\n\t * @param callback - The callback to remove.\n\t */\n\tremoveListener(event: string, callback: (value?: any) => void): boolean {\n\t\treturn this.store.db.removeListener(event, callback);\n\t}\n\n\t/**\n\t * Get or create a transaction log instance.\n\t *\n\t * @param name - The name of the transaction log.\n\t * @returns The transaction log.\n\t */\n\tuseLog(name: string | number): TransactionLog {\n\t\treturn this.store.useLog(this._context, name);\n\t}\n}\n","/**\n * A minimal, dependency-free streaming USTAR (POSIX tar) encoder.\n *\n * Built for streaming whole-database backups: the set of live RocksDB files\n * (SSTs, blobs, MANIFEST, CURRENT, OPTIONS, WAL) is serialized into a single\n * tar byte stream that can be piped to any destination and unpacked with\n * standard tools (`tar -xf`). The encoder never buffers a whole file — each\n * entry's payload is streamed through in chunks — so peak memory stays flat\n * regardless of database size.\n *\n * Backpressure is the caller's lever: every method `await`s the {@link TarSink},\n * so wiring the sink to a stream writer's `write()` naturally paces production\n * to the consumer.\n *\n * Only what a RocksDB backup needs is implemented: regular files. Paths longer\n * than USTAR's 100-byte `name` field are split across the `name` and `prefix`\n * fields (~255 bytes total), which covers `transaction_logs/<store>/<file>`\n * entries; GNU/pax long-name extensions are not implemented, so a path that\n * still doesn't fit throws rather than being silently truncated. File sizes\n * larger than the octal `size` field can hold (~8 GiB) fall back to the GNU\n * base-256 encoding.\n */\n\n/** Size of a tar block. Every header and the archive length are multiples of this. */\nconst BLOCK_SIZE = 512;\n\n/** Maximum bytes for the USTAR `name` field. */\nconst MAX_NAME_LENGTH = 100;\n\n/** Maximum bytes for the USTAR `prefix` field (holds the leading directories). */\nconst MAX_PREFIX_LENGTH = 155;\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder();\n\n/**\n * Destination for encoded bytes. Returning a promise applies backpressure: the\n * encoder will not produce the next chunk until it resolves. Chunks must be\n * consumed (or copied) before the returned promise resolves, since the encoder\n * may reuse or hand back borrowed buffers afterward.\n */\nexport type TarSink = (chunk: Uint8Array) => void | Promise<void>;\n\n/**\n * Per-entry tar metadata. All fields are cosmetic for backup/restore (RocksDB\n * does not consult them); they exist so the archive is well-formed for external\n * tools.\n */\nexport type TarEntryOptions = {\n\t/** Unix file mode, masked to 12 bits. Default `0o644`. */\n\tmode?: number;\n\t/**\n\t * Modification time in seconds since the epoch. Default `0` so archives are\n\t * reproducible (byte-identical for identical inputs).\n\t */\n\tmtime?: number;\n};\n\n/**\n * Writes a UTF-8 string into a fixed-width header field, left-justified and\n * NUL-padded (the block is already zero-filled, so nothing else is needed).\n * Throws if the encoded value does not fit — tar fields are silently lossy\n * otherwise, which corrupts the archive.\n */\nfunction writeField(block: Uint8Array, value: string, offset: number, length: number): void {\n\tconst bytes = textEncoder.encode(value);\n\tif (bytes.length > length) {\n\t\tthrow new RangeError(`tar field value ${JSON.stringify(value)} exceeds ${length} bytes`);\n\t}\n\tblock.set(bytes, offset);\n}\n\n/**\n * Writes a non-negative integer as a NUL-terminated, zero-padded octal string\n * into a `length`-byte field (so `length - 1` octal digits). Values too large\n * for octal fall back to the GNU base-256 extension, where the high bit of the\n * first byte is set and the magnitude is stored big-endian in the remainder.\n */\nfunction writeOctal(block: Uint8Array, value: number, offset: number, length: number): void {\n\tconst digits = length - 1;\n\tif (value > 8 ** digits - 1) {\n\t\t// GNU base-256: signal byte 0x80, then big-endian magnitude. JS safe\n\t\t// integers are 53 bits, well within the (length - 1) * 8 bits available.\n\t\tlet v = value;\n\t\tfor (let i = offset + length - 1; i > offset; i--) {\n\t\t\tblock[i] = v & 0xff;\n\t\t\tv = Math.floor(v / 256);\n\t\t}\n\t\tblock[offset] = 0x80;\n\t\treturn;\n\t}\n\tconst str = value.toString(8).padStart(digits, '0');\n\tfor (let i = 0; i < digits; i++) {\n\t\tblock[offset + i] = str.charCodeAt(i);\n\t}\n\t// block[offset + digits] stays 0 (NUL terminator).\n}\n\n/**\n * Computes and writes the USTAR header checksum: the unsigned sum of all 512\n * header bytes with the checksum field itself taken as ASCII spaces. Stored as\n * six octal digits, a NUL, then a space (the conventional encoding).\n */\nfunction writeChecksum(block: Uint8Array): void {\n\tfor (let i = 148; i < 156; i++) {\n\t\tblock[i] = 0x20; // spaces during computation\n\t}\n\tlet sum = 0;\n\tfor (let i = 0; i < BLOCK_SIZE; i++) {\n\t\tsum += block[i];\n\t}\n\tconst str = sum.toString(8).padStart(6, '0');\n\tfor (let i = 0; i < 6; i++) {\n\t\tblock[148 + i] = str.charCodeAt(i);\n\t}\n\tblock[154] = 0; // NUL\n\tblock[155] = 0x20; // space\n}\n\n/**\n * Splits a path into USTAR `name` (<=100 bytes) and `prefix` (<=155 bytes)\n * fields at a `/` boundary; a reader rejoins them as `prefix + \"/\" + name`.\n * Returns an empty prefix when the whole path fits in `name`. Throws when the\n * path cannot be represented — a trailing component over 100 bytes, or leading\n * directories that don't fit in 155. RocksDB and transaction-log filenames never\n * hit this; only a pathological log-store name would.\n */\nfunction splitTarName(path: string): { name: string; prefix: string } {\n\t// Encode once and search the bytes: `/` is ASCII and UTF-8 never embeds an\n\t// ASCII byte inside a multi-byte sequence, so every 0x2f byte is a real\n\t// separator and both halves of a split there are valid UTF-8.\n\tconst encoded = textEncoder.encode(path);\n\tif (encoded.length <= MAX_NAME_LENGTH) {\n\t\treturn { name: path, prefix: '' };\n\t}\n\tlet best = -1;\n\tfor (let i = 0; i < encoded.length; i++) {\n\t\tif (encoded[i] !== 0x2f) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst prefixLength = i;\n\t\tconst nameLength = encoded.length - i - 1;\n\t\tif (nameLength > 0 && nameLength <= MAX_NAME_LENGTH && prefixLength <= MAX_PREFIX_LENGTH) {\n\t\t\t// As the split moves right the prefix grows and the name shrinks, so the\n\t\t\t// last split satisfying both bounds packs the most into `prefix`.\n\t\t\tbest = i;\n\t\t}\n\t}\n\tif (best === -1) {\n\t\tthrow new RangeError(\n\t\t\t`tar entry name ${JSON.stringify(path)} does not fit the USTAR name (<=${MAX_NAME_LENGTH}) + prefix (<=${MAX_PREFIX_LENGTH}) fields`\n\t\t);\n\t}\n\treturn {\n\t\tname: textDecoder.decode(encoded.subarray(best + 1)),\n\t\tprefix: textDecoder.decode(encoded.subarray(0, best)),\n\t};\n}\n\n/**\n * Builds a single 512-byte USTAR header block for a regular file. Long paths are\n * split across the `name` and `prefix` fields (see {@link splitTarName}).\n */\nfunction buildHeader(name: string, size: number, mode: number, mtime: number): Uint8Array {\n\tconst block = new Uint8Array(BLOCK_SIZE);\n\tconst split = splitTarName(name);\n\twriteField(block, split.name, 0, MAX_NAME_LENGTH);\n\twriteOctal(block, mode & 0o7777, 100, 8); // mode\n\twriteOctal(block, 0, 108, 8); // uid\n\twriteOctal(block, 0, 116, 8); // gid\n\twriteOctal(block, size, 124, 12); // size\n\twriteOctal(block, Math.floor(mtime), 136, 12); // mtime (floored — octal field, no fraction)\n\tblock[156] = 0x30; // typeflag '0' = regular file\n\twriteField(block, 'ustar', 257, 6); // magic \"ustar\\0\"\n\tblock[263] = 0x30; // version \"00\"\n\tblock[264] = 0x30;\n\tif (split.prefix.length > 0) {\n\t\twriteField(block, split.prefix, 345, MAX_PREFIX_LENGTH); // prefix\n\t}\n\twriteChecksum(block);\n\treturn block;\n}\n\n/**\n * Streaming USTAR encoder. Usage is a strict sequence per file —\n * {@link TarEncoder.addFile} once, then {@link TarEncoder.writeData} until the\n * declared size is reached — followed by a single {@link TarEncoder.finalize}:\n *\n * ```ts\n * const tar = new TarEncoder((chunk) => writer.write(chunk));\n * await tar.addFile('CURRENT', current.length);\n * await tar.writeData(current);\n * await tar.addFile('000123.sst', sstSize);\n * for await (const chunk of sstChunks) await tar.writeData(chunk);\n * await tar.finalize();\n * ```\n *\n * The size passed to `addFile` is authoritative: tar records it in the header\n * before any payload, so it must be known up front (it is — RocksDB's\n * `GetLiveFilesStorageInfo` returns each file's exact size). Writing more or\n * fewer bytes than declared throws.\n */\nexport class TarEncoder {\n\t#sink: TarSink;\n\t/** Payload bytes still expected for the current entry. */\n\t#remaining: number = 0;\n\t/** Zero-padding bytes owed after the current entry's payload reaches a block boundary. */\n\t#pad: number = 0;\n\t#finalized: boolean = false;\n\n\tconstructor(sink: TarSink) {\n\t\tthis.#sink = sink;\n\t}\n\n\t/**\n\t * Emits the header for a new file entry. Must be preceded by completing any\n\t * prior entry's payload. After this, exactly `size` bytes must be supplied\n\t * via {@link TarEncoder.writeData} before the next `addFile` or `finalize`.\n\t */\n\tasync addFile(name: string, size: number, options?: TarEntryOptions): Promise<void> {\n\t\tif (this.#finalized) {\n\t\t\tthrow new Error('TarEncoder already finalized');\n\t\t}\n\t\tif (this.#remaining !== 0) {\n\t\t\tthrow new Error(`previous tar entry incomplete: ${this.#remaining} byte(s) unwritten`);\n\t\t}\n\t\tif (!Number.isInteger(size) || size < 0) {\n\t\t\tthrow new RangeError('tar entry size must be a non-negative integer');\n\t\t}\n\t\t// Build the header first so an invalid/unsplittable name throws before any\n\t\t// encoder state is mutated.\n\t\tconst header = buildHeader(name, size, options?.mode ?? 0o644, options?.mtime ?? 0);\n\t\tthis.#remaining = size;\n\t\tthis.#pad = (BLOCK_SIZE - (size % BLOCK_SIZE)) % BLOCK_SIZE;\n\t\tawait this.#sink(header);\n\t}\n\n\t/**\n\t * Streams a chunk of the current entry's payload. Chunks may be any size; the\n\t * total across all `writeData` calls for an entry must equal the size passed\n\t * to {@link TarEncoder.addFile}. Block padding is emitted automatically once\n\t * the final byte of an entry is written.\n\t */\n\tasync writeData(chunk: Uint8Array): Promise<void> {\n\t\tif (this.#finalized) {\n\t\t\tthrow new Error('TarEncoder already finalized');\n\t\t}\n\t\tif (chunk.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tif (chunk.length > this.#remaining) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`tar data overruns entry size by ${chunk.length - this.#remaining} byte(s)`\n\t\t\t);\n\t\t}\n\t\tthis.#remaining -= chunk.length;\n\t\tawait this.#sink(chunk);\n\t\tif (this.#remaining === 0 && this.#pad > 0) {\n\t\t\tconst pad = this.#pad;\n\t\t\tthis.#pad = 0;\n\t\t\tawait this.#sink(new Uint8Array(pad));\n\t\t}\n\t}\n\n\t/**\n\t * Convenience for an entry whose contents are already fully in memory (e.g.\n\t * the small `CURRENT`/`OPTIONS` files RocksDB returns inline).\n\t */\n\tasync addFileData(name: string, data: Uint8Array, options?: TarEntryOptions): Promise<void> {\n\t\tawait this.addFile(name, data.length, options);\n\t\tawait this.writeData(data);\n\t}\n\n\t/**\n\t * Writes the two zero-filled blocks that mark end-of-archive. The encoder is\n\t * unusable afterward. Throws if the current entry is not fully written, so a\n\t * truncated stream cannot be silently finalized into a valid-looking archive.\n\t */\n\tasync finalize(): Promise<void> {\n\t\tif (this.#finalized) {\n\t\t\tthrow new Error('TarEncoder already finalized');\n\t\t}\n\t\tif (this.#remaining !== 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`cannot finalize: current tar entry has ${this.#remaining} byte(s) unwritten`\n\t\t\t);\n\t\t}\n\t\tthis.#finalized = true;\n\t\tawait this.#sink(new Uint8Array(BLOCK_SIZE * 2));\n\t}\n}\n","import type { NativeDatabase } from './load-binding.js';\nimport { TarEncoder } from './tar.js';\n\n/**\n * Options for streaming a backup via `db.backup(stream)`.\n */\nexport interface BackupStreamOptions {\n\t/**\n\t * Flush the memtable before streaming. Defaults to `true` when the database\n\t * was opened with `disableWAL` (otherwise unflushed data would be missing\n\t * from the stream), and `false` otherwise — matching `db.backup(dir)`.\n\t */\n\tflushBeforeBackup?: boolean;\n\n\t/**\n\t * Gzip-compress the archive before writing it to the stream, producing a\n\t * `.tar.gz` stream instead of a plain `.tar`. Defaults to `false`.\n\t *\n\t * Compression runs in the runtime's `CompressionStream`, downstream of the tar\n\t * encoder, so end-to-end backpressure is preserved. RocksDB SST files are\n\t * usually already block-compressed, so the additional savings vary with the\n\t * data and the configured compression.\n\t */\n\tgzip?: boolean;\n\n\t/**\n\t * Also stream the transaction log store as `transaction_logs/<store>/…`\n\t * entries (each `*.txnlog` and `txn.state` file) after the database files.\n\t * Defaults to `false`. Extraction reconstructs them next to the database, and\n\t * their mtimes are preserved so the store's age-based rotation/retention stays\n\t * correct.\n\t */\n\ttransactionLogs?: boolean;\n}\n\n/** Native event discriminator: a new file header (vs. a payload chunk). */\nconst EVENT_FILE = 0;\n\n/**\n * Streams a consistent snapshot of the database to a `WritableStream` as a tar\n * archive, with no intermediate copy on disk. The set of live RocksDB files is\n * enumerated and read natively; each file header and payload chunk is framed\n * into the {@link TarEncoder} here in JS and written to `stream`.\n *\n * Backpressure flows end to end: the encoder awaits each `writer.write()`, and\n * the native producer awaits each `emit()` before reading the next chunk, so a\n * slow consumer paces the entire pipeline rather than buffering in memory.\n *\n * The resulting archive can be unpacked with any tar tool (`tar -xf`) into a\n * directory that opens directly as a RocksDB database.\n */\nexport async function backupToStream(\n\tdb: NativeDatabase,\n\tstream: WritableStream<Uint8Array>,\n\toptions?: BackupStreamOptions\n): Promise<void> {\n\t// With `gzip`, the tar bytes are written into a CompressionStream whose\n\t// compressed output is piped to the caller's stream. `pipeTo` propagates\n\t// backpressure and, on failure, aborts the destination — so the end-to-end\n\t// pacing and error handling carry through the compressor unchanged.\n\tlet tarDestination: WritableStream<Uint8Array>;\n\tlet piped: Promise<void> | undefined;\n\tif (options?.gzip) {\n\t\tconst gzip = new CompressionStream('gzip');\n\t\tpiped = gzip.readable.pipeTo(stream);\n\t\ttarDestination = gzip.writable as WritableStream<Uint8Array>;\n\t} else {\n\t\ttarDestination = stream;\n\t}\n\n\tconst writer = tarDestination.getWriter();\n\tconst tar = new TarEncoder((chunk) => writer.write(chunk));\n\n\t// Native invokes `emit` once per file header and once per payload chunk, and\n\t// awaits the returned promise before producing the next event. A rejection\n\t// here (e.g. the consumer errored) aborts the native stream.\n\tconst emit = async (\n\t\tkind: number,\n\t\tdata: string | Uint8Array,\n\t\tsize: number,\n\t\tmtime: number\n\t): Promise<void> => {\n\t\tif (kind === EVENT_FILE) {\n\t\t\tawait tar.addFile(data as string, size, { mtime });\n\t\t} else {\n\t\t\tawait tar.writeData(data as Uint8Array);\n\t\t}\n\t};\n\n\ttry {\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tdb.backupStream(resolve, reject, emit, options);\n\t\t});\n\t\tawait tar.finalize();\n\t\tawait writer.close();\n\t\t// Closing the tar destination flushes and closes the compressor, which\n\t\t// closes its readable end and lets the pipe finish writing to the caller.\n\t\tif (piped) {\n\t\t\tawait piped;\n\t\t}\n\t} catch (err) {\n\t\t// Surface the failure to the consumer and release the writer lock. The\n\t\t// writer may already be errored (consumer-side failure), so ignore abort\n\t\t// rejections and rethrow the original cause.\n\t\tawait writer.abort(err).catch(() => {});\n\t\t// Aborting the compressor rejects the pipe; settle it so the rejection is\n\t\t// observed rather than surfacing as an unhandled rejection.\n\t\tif (piped) {\n\t\t\tawait piped.catch(() => {});\n\t\t}\n\t\tthrow err;\n\t}\n}\n","import type { BufferWithDataView, Key } from './encoding.js';\nimport { constants, type NativeIteratorCls, type NativeIteratorResult } from './load-binding.js';\nimport { ITERATOR_STATE, KEY_BUFFER, type Store, VALUE_BUFFER } from './store.js';\n\nconst { ITERATOR_RESULT_DONE, ITERATOR_RESULT_FAST } = constants;\n\nexport interface DBIteratorValue<T> {\n\tkey: Key;\n\tvalue: T;\n}\n\nconst DONE_RESULT: IteratorResult<DBIteratorValue<unknown>> = Object.freeze({\n\tdone: true,\n\tvalue: undefined as unknown,\n}) as IteratorResult<DBIteratorValue<unknown>>;\n\n/**\n * Wraps the `NativeIterator` C++ binding, decoding keys and values from the\n * shared key/value buffers (fast path) or from per-iteration buffers (slow\n * fallback path used for oversized data or stable-buffer decoders).\n *\n * The native `next()` returns a primitive signal (and writes lengths to the\n * shared `ITERATOR_STATE` buffer) instead of constructing a JS result object,\n * so this class is responsible for building the `IteratorResult`.\n */\nexport class DBIterator<T> implements Iterator<DBIteratorValue<T>> {\n\titerator: InstanceType<typeof NativeIteratorCls>;\n\tstore: Store;\n\t#includeValues: boolean;\n\t// When set, iteration stops after this many entries. The native iterator has no\n\t// notion of a count bound, so the limit is enforced here in the JS layer.\n\t#limit: number | undefined;\n\t#yielded = 0;\n\n\tconstructor(\n\t\titerator: InstanceType<typeof NativeIteratorCls>,\n\t\tstore: Store,\n\t\tincludeValues: boolean,\n\t\tlimit?: number\n\t) {\n\t\tthis.iterator = iterator;\n\t\tthis.store = store;\n\t\tthis.#includeValues = includeValues;\n\t\t// Normalize a nullish limit to `undefined` (no limit). A caller passing `null` must not be\n\t\t// read as a 0 limit by the `#yielded >= this.#limit` check below (null coerces to 0).\n\t\tthis.#limit = limit ?? undefined;\n\t}\n\n\t[Symbol.iterator](): Iterator<DBIteratorValue<T>> {\n\t\treturn this;\n\t}\n\n\tnext(): IteratorResult<DBIteratorValue<T>> {\n\t\tif (this.#limit !== undefined && this.#yielded >= this.#limit) {\n\t\t\t// Reached the requested limit: release the native iterator and stop.\n\t\t\tthis.iterator.return?.();\n\t\t\treturn DONE_RESULT as IteratorResult<DBIteratorValue<T>>;\n\t\t}\n\n\t\tconst result: NativeIteratorResult = this.iterator.next();\n\n\t\tif (result === ITERATOR_RESULT_DONE) {\n\t\t\treturn DONE_RESULT as IteratorResult<DBIteratorValue<T>>;\n\t\t}\n\n\t\tthis.#yielded++;\n\t\tconst includeValues = this.#includeValues;\n\t\tconst value: Partial<DBIteratorValue<T>> = {};\n\n\t\tif (result === ITERATOR_RESULT_FAST) {\n\t\t\t// Fast path: key bytes are in the shared KEY_BUFFER, value bytes\n\t\t\t// are in the shared VALUE_BUFFER, and lengths are in ITERATOR_STATE.\n\t\t\tvalue.key = this.store.readKey(KEY_BUFFER, 0, ITERATOR_STATE[0]);\n\t\t\tif (includeValues) {\n\t\t\t\tVALUE_BUFFER.end = ITERATOR_STATE[1];\n\t\t\t\tvalue.value = this.store.decodeValue(VALUE_BUFFER) as T;\n\t\t\t}\n\t\t} else {\n\t\t\t// Slow path: data didn't fit in shared buffers (or decoder needs\n\t\t\t// stable buffer). The native side allocated fresh buffers for us.\n\t\t\tconst slow = result as { key: Buffer; value?: Buffer };\n\t\t\tvalue.key = this.store.decodeKey(slow.key);\n\t\t\tif (includeValues && slow.value !== undefined) {\n\t\t\t\tvalue.value = this.store.decodeValue(slow.value as BufferWithDataView) as T;\n\t\t\t}\n\t\t}\n\n\t\treturn { done: false, value: value as DBIteratorValue<T> };\n\t}\n\n\treturn(value?: any): IteratorResult<DBIteratorValue<T>, any> {\n\t\tthis.iterator.return?.();\n\t\treturn { done: true, value };\n\t}\n\n\tthrow(err: unknown): IteratorResult<DBIteratorValue<T>, any> {\n\t\tthis.iterator.throw?.(err);\n\t\tthrow err;\n\t}\n}\n","import * as orderedBinary from 'ordered-binary';\n\nexport type Key = Key[] | string | symbol | number | boolean | Uint8Array | Buffer | null;\n\nexport interface BufferWithDataView extends Buffer {\n\tdataView: DataView;\n\tstart: number;\n\tend: number;\n}\n\nexport type EncoderFunction = new (options?: any) => Encoder;\n\nexport interface Encoder {\n\tcopyBuffers?: boolean;\n\tdecode?: (buffer: BufferWithDataView, options?: { end: number }) => any;\n\tencode?: (value: any, mode?: number) => Buffer; // | string;\n\tEncoder?: EncoderFunction;\n\tfreezeData?: boolean;\n\tname?: string;\n\tneedsStableBuffer?: boolean;\n\trandomAccessStructure?: boolean;\n\treadKey?: (buffer: Buffer, start: number, end: number, inSequence?: boolean) => any;\n\tstructuredClone?: boolean;\n\tstructures?: any[];\n\tuseFloat32?: boolean;\n\twriteKey?: (key: any, target: Buffer, position: number, inSequence?: boolean) => number;\n}\n\nexport type Encoding = 'binary' | 'ordered-binary' | 'msgpack' | false;\n\nexport interface KeyEncoder {\n\treadKey?: ReadKeyFunction<Key>;\n\twriteKey?: WriteKeyFunction;\n}\n\nexport type KeyEncoding = 'binary' | 'ordered-binary' | 'uint32';\n\nexport type ReadKeyFunction<T> = (source: BufferWithDataView, start: number, end?: number) => T;\nexport type WriteKeyFunction = (key: Key, target: BufferWithDataView, start: number) => number;\n\n/**\n * Initializes the key encoder functions.\n *\n * @param keyEncoding - The key encoding to use.\n * @param keyEncoder - The key encoder to use.\n * @returns The key encoder.\n */\nexport function initKeyEncoder(\n\trequestedKeyEncoding?: KeyEncoding | undefined,\n\tkeyEncoder?: KeyEncoder | undefined\n): { keyEncoding: KeyEncoding; readKey: ReadKeyFunction<Key>; writeKey: WriteKeyFunction } {\n\tconst keyEncoding: KeyEncoding = requestedKeyEncoding ?? 'ordered-binary';\n\n\tif (keyEncoder) {\n\t\tconst { readKey, writeKey } = keyEncoder;\n\t\tif (!readKey || !writeKey) {\n\t\t\tthrow new Error('Custom key encoder must provide both readKey and writeKey');\n\t\t}\n\t\treturn { keyEncoding, readKey, writeKey };\n\t}\n\n\tif (keyEncoding === 'binary') {\n\t\treturn {\n\t\t\tkeyEncoding,\n\t\t\treadKey(source: BufferWithDataView, start: number, end?: number): Uint8Array {\n\t\t\t\treturn Uint8Array.prototype.slice.call(source, start, end);\n\t\t\t},\n\t\t\twriteKey(key: Key, target: BufferWithDataView, start: number): number {\n\t\t\t\tconst keyBuffer = key instanceof Buffer ? key : Buffer.from(String(key));\n\t\t\t\ttarget.set(keyBuffer, start);\n\t\t\t\treturn keyBuffer.length + start;\n\t\t\t},\n\t\t};\n\t}\n\n\tif (keyEncoding === 'uint32') {\n\t\treturn {\n\t\t\tkeyEncoding,\n\t\t\treadKey(source: BufferWithDataView, start: number, _end?: number): number {\n\t\t\t\tif (!source.dataView) {\n\t\t\t\t\tsource.dataView = new DataView(source.buffer);\n\t\t\t\t}\n\t\t\t\treturn source.dataView.getUint32(start, true);\n\t\t\t},\n\t\t\twriteKey(key: Key, target: BufferWithDataView, start: number): number {\n\t\t\t\tconst keyNumber = Number(key);\n\t\t\t\tif (isNaN(keyNumber)) {\n\t\t\t\t\tthrow new TypeError('Key is not a number');\n\t\t\t\t}\n\t\t\t\ttarget.dataView.setUint32(start, keyNumber, true);\n\t\t\t\treturn start + 4;\n\t\t\t},\n\t\t};\n\t}\n\n\tif (keyEncoding === 'ordered-binary') {\n\t\treturn {\n\t\t\tkeyEncoding,\n\t\t\treadKey: orderedBinary.readKey,\n\t\t\twriteKey: orderedBinary.writeKey as WriteKeyFunction,\n\t\t};\n\t}\n\n\tthrow new Error(`Invalid key encoding: ${keyEncoding}`);\n}\n\n/**\n * Creates a fixed-size buffer with a data view, start, and end properties.\n *\n * Note: It uses `Buffer.allocUnsafe()` because it's the fastest by using\n * Node.js's preallocated memory pool, though the memory is not zeroed out.\n *\n * @param size - The size of the buffer.\n * @returns The buffer with a data view.\n */\nexport function createFixedBuffer(size: number): BufferWithDataView {\n\tconst buffer = Buffer.allocUnsafeSlow(size) as BufferWithDataView;\n\tbuffer.dataView = new DataView(buffer.buffer);\n\tbuffer.start = 0;\n\tbuffer.end = 0;\n\treturn buffer;\n}\n","import { type BackupStreamOptions, backupToStream } from './backup-stream.js';\nimport { assertBackupDirOutsideDatabase, type BackupOptions } from './backup.js';\nimport { DBIterator, type DBIteratorValue } from './dbi-iterator.js';\nimport type { DBITransactional, IteratorOptions, RangeOptions } from './dbi.js';\nimport {\n\ttype BufferWithDataView,\n\tcreateFixedBuffer,\n\ttype Encoder,\n\tEncoding,\n\tinitKeyEncoder,\n\ttype Key,\n\ttype KeyEncoding,\n\ttype ReadKeyFunction,\n\ttype WriteKeyFunction,\n} from './encoding.js';\nimport {\n\tconstants,\n\tNativeDatabase,\n\ttype NativeDatabaseOptions,\n\tNativeIterator,\n\tNativeTransaction,\n\tstats,\n\tsupportedCompression,\n\ttype TransactionLog,\n\ttype UserSharedBufferCallback,\n} from './load-binding.js';\nimport { parseDuration } from './util.js';\nimport { ExtendedIterable } from '@harperfast/extended-iterable';\n\nconst {\n\tONLY_IF_IN_MEMORY_CACHE_FLAG,\n\tNOT_IN_MEMORY_CACHE_FLAG,\n\tALWAYS_CREATE_NEW_BUFFER_FLAG,\n\tFRESH_VERSION_FLAG,\n\tPOPULATE_VERSION_FLAG,\n\tITERATOR_REVERSE_FLAG,\n\tITERATOR_INCLUSIVE_END_FLAG,\n\tITERATOR_EXCLUSIVE_START_FLAG,\n\tITERATOR_INCLUDE_VALUES_FLAG,\n\tITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG,\n\tITERATOR_CONTEXT_IS_TRANSACTION_FLAG,\n} = constants;\nconst KEY_BUFFER_SIZE = 4096;\n\nexport const KEY_BUFFER: BufferWithDataView = createFixedBuffer(KEY_BUFFER_SIZE);\nexport const VALUE_BUFFER: BufferWithDataView = createFixedBuffer(64 * 1024);\n\n/**\n * Backing buffer for the shared iterator state. Layout (Uint32Array view):\n * [0] = key length written into KEY_BUFFER by the most recent iterator step\n * [1] = value length written into VALUE_BUFFER by the most recent step\n */\nexport const ITERATOR_STATE_BUFFER: Buffer = Buffer.allocUnsafeSlow(8);\nexport const ITERATOR_STATE: Uint32Array = new Uint32Array(\n\tITERATOR_STATE_BUFFER.buffer,\n\tITERATOR_STATE_BUFFER.byteOffset,\n\t2\n);\n\nconst MAX_KEY_SIZE = 1024 * 1024; // 1MB\nconst RESET_BUFFER_MODE = 1024;\nconst REUSE_BUFFER_MODE = 512;\nconst SAVE_BUFFER_SIZE = 8192;\n// const WRITE_BUFFER_SIZE = 65536;\n\nexport type StoreContext = NativeDatabase | NativeTransaction;\nexport type StoreGetOptions = GetOptions & DBITransactional;\nexport type StoreIteratorOptions = IteratorOptions & DBITransactional;\nexport type StorePutOptions = PutOptions & DBITransactional;\nexport type StoreRangeOptions = RangeOptions & DBITransactional;\nexport type StoreRemoveOptions = DBITransactional | unknown;\n\nexport type CompactOptions = {\n\tstart?: Key;\n\tend?: Key;\n\t/**\n\t * Compact the bottommost level as well, rewriting every file in range.\n\t *\n\t * RocksDB skips the bottommost level by default when no compaction filter is installed, and\n\t * that is where most of the data sits — so an ordinary `compact()` leaves it untouched. Since a\n\t * changed `compression` algorithm only governs newly written files, rewriting that level is the\n\t * only way to re-encode data that already exists.\n\t *\n\t * This rewrites the whole range regardless of whether RocksDB considers it worth doing, so it\n\t * is as expensive as the data is large. Defaults to `false`.\n\t */\n\tbottommost?: boolean;\n};\n\n/**\n * A RocksDB block/blob compression algorithm. Which algorithms are actually\n * available depends on the libraries the native binding was compiled with —\n * check `supportedCompression` at runtime. `'none'` disables compression and\n * is always available.\n */\nexport type CompressionAlgorithm =\n\t| 'none'\n\t| 'snappy'\n\t| 'zlib'\n\t| 'bzip2'\n\t| 'lz4'\n\t| 'lz4hc'\n\t| 'xpress'\n\t| 'zstd';\n\n/**\n * The `compression` open option: either an algorithm name, or an object with\n * an algorithm and an optional level (forwarded to RocksDB's\n * `compression_opts.level`; meaning is algorithm-specific).\n */\nexport type CompressionOption =\n\t| CompressionAlgorithm\n\t| { algorithm: CompressionAlgorithm; level?: number };\n\n/**\n * The compression currently in effect for a column family, as returned by the\n * `compression` getter. `level` is present only when a non-default compression\n * level is configured.\n */\nexport type CompressionInfo = {\n\talgorithm: CompressionAlgorithm;\n\tlevel?: number;\n};\n\n/**\n * Normalizes the public `compression` option into the primitive fields the\n * native layer expects. When `option` is omitted, or is an object without an\n * `algorithm`, returns an empty object and lets the native layer apply the\n * default (LZ4 when the build supports it, else RocksDB's own default).\n * Throws a `TypeError` for a malformed option and an\n * `Error` for an algorithm that isn't supported by this build.\n */\nexport function normalizeCompression(option: CompressionOption | undefined): {\n\tcompression?: string;\n\tcompressionLevel?: number;\n} {\n\t// When unset, leave compression to the native layer, which defaults to LZ4\n\t// when the build supports it (see Database::Open).\n\tif (option === undefined || option === null) {\n\t\treturn {};\n\t}\n\n\tlet algorithm: string;\n\tlet level: number | undefined;\n\n\tif (typeof option === 'string') {\n\t\talgorithm = option;\n\t} else if (typeof option === 'object' && !Array.isArray(option)) {\n\t\tif (option.algorithm === undefined || option.algorithm === null) {\n\t\t\tif (option.level !== undefined && option.level !== null) {\n\t\t\t\tthrow new TypeError('Compression level cannot be specified without an algorithm');\n\t\t\t}\n\t\t\treturn {};\n\t\t}\n\t\talgorithm = option.algorithm;\n\t\tif (option.level !== undefined && option.level !== null) {\n\t\t\t// TypeScript types `level` as a number. Accept a numeric string too (a\n\t\t\t// common shape from loosely-typed config), but do NOT let bare `Number()`\n\t\t\t// coerce other loose inputs — `true`, `[]`, `[6]`, and `''`/whitespace all\n\t\t\t// become numbers and would silently mis-tune or drop compression. Anything\n\t\t\t// that is not a number or a non-blank numeric string is rejected.\n\t\t\tconst raw = option.level as unknown;\n\t\t\tconst coerced =\n\t\t\t\ttypeof raw === 'number'\n\t\t\t\t\t? raw\n\t\t\t\t\t: typeof raw === 'string' && raw.trim() !== ''\n\t\t\t\t\t\t? Number(raw)\n\t\t\t\t\t\t: Number.NaN;\n\t\t\tif (!Number.isInteger(coerced) || coerced < -2147483648 || coerced > 2147483647) {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`compression level must be a 32-bit integer, got ${JSON.stringify(option.level)}`\n\t\t\t\t);\n\t\t\t}\n\t\t\tlevel = coerced;\n\t\t}\n\t} else {\n\t\tthrow new TypeError('compression must be an algorithm name or an { algorithm, level } object');\n\t}\n\n\tif (!supportedCompression.includes(algorithm)) {\n\t\tthrow new Error(\n\t\t\t`Unsupported compression algorithm \"${algorithm}\". This build supports: ${supportedCompression.join(', ')}`\n\t\t);\n\t}\n\n\treturn { compression: algorithm, compressionLevel: level };\n}\n\n/**\n * Options for the `Store` class.\n */\nexport interface StoreOptions extends Omit<\n\tNativeDatabaseOptions,\n\t'compression' | 'compressionLevel' | 'mode' | 'transactionLogRetentionMs'\n> {\n\t/**\n\t * The block/blob compression algorithm for this column family. Accepts an\n\t * algorithm name (`'lz4'`, `'zstd'`, `'none'`, ...) or an object with an\n\t * `algorithm` and optional `level`. Applies to both SST blocks and blob\n\t * files (large values). Which algorithms are available depends on the native\n\t * build — see `supportedCompression`.\n\t *\n\t * When omitted, defaults to `lz4` if the build supports it, otherwise\n\t * RocksDB's own default (Snappy when linked, else no compression).\n\t * Compression is a dynamically-changeable option: reopening with a\n\t * different algorithm governs subsequently written files; existing files\n\t * keep their compression until rewritten by compaction. Use the\n\t * `compression` getter to read the value currently in effect.\n\t *\n\t * @default 'lz4'\n\t */\n\tcompression?: CompressionOption;\n\n\t/**\n\t * Apply `compression` to every column family in the database, not only the one being opened.\n\t *\n\t * RocksDB opens all of a database's column families in a single native call, and by default\n\t * each of the ones you did not name keeps its persisted algorithm. That is right when codecs\n\t * are chosen per table, but it leaves a caller that wants one codec for the whole database\n\t * unable to say so: those families are already open at their old algorithm before it gets a\n\t * chance to ask, and a column family's compression cannot be changed while it is open.\n\t *\n\t * Setting this applies the requested algorithm to all of them instead — including families\n\t * that were persisted with a different one, which is the point when adopting a codec on a\n\t * database that predates it.\n\t *\n\t * Only meaningful with an explicit `compression` (it throws otherwise), and only on the open\n\t * that actually creates the database handle; later opens of the same path reuse that handle\n\t * and cannot revisit the decision. As always, the algorithm governs newly written files —\n\t * existing SST/blob files keep theirs until rewritten (see `compact({ bottommost: true })`).\n\t *\n\t * @default false\n\t */\n\tcompressionForAllColumnFamilies?: boolean;\n\n\tdecoder?: Encoder | null;\n\tencoder?: Encoder | null;\n\tencoding?: Encoding;\n\tfreezeData?: boolean;\n\tkeyEncoder?: { readKey?: ReadKeyFunction<Key>; writeKey?: WriteKeyFunction };\n\tkeyEncoding?: KeyEncoding;\n\t// mapSize?: number;\n\t// maxDbs?: number;\n\t// maxFreeSpaceToLoad?: number;\n\t// maxFreeSpaceToRetain?: number;\n\t// maxReaders?: number;\n\tmaxKeySize?: number;\n\t// noReadAhead?: boolean;\n\t// noSync?: boolean;\n\t// overlappingSync?: boolean;\n\t// pageSize?: number;\n\tpessimistic?: boolean;\n\n\t/**\n\t * If `true`, the encoder will use a random access structure.\n\t */\n\trandomAccessStructure?: boolean;\n\n\t/**\n\t * When `true`, the database is opened in read-only mode. Write operations\n\t * will throw an error with code `ERR_DATABASE_READONLY`.\n\t */\n\treadOnly?: boolean;\n\n\tsharedStructuresKey?: symbol;\n\n\t/**\n\t * A string containing the amount of time or the number of milliseconds to\n\t * retain transaction logs before purging.\n\t *\n\t * @default '3d' (3 days)\n\t */\n\ttransactionLogRetention?: number | string;\n\n\t// trackMetrics?: boolean;\n}\n\n/**\n * Options for the `getUserSharedBuffer()` method.\n */\nexport type UserSharedBufferOptions = { callback?: UserSharedBufferCallback };\n\n/**\n * The return type of `getUserSharedBuffer()`.\n */\nexport type ArrayBufferWithNotify = ArrayBuffer & {\n\tcancel: () => void;\n\tnotify: () => void;\n};\n\n/**\n * A store wraps the `NativeDatabase` binding and database settings so that a\n * single database instance can be shared between the main `RocksDatabase`\n * instance and the `Transaction` instance.\n *\n * A store is bound to a single `RocksDatabase` instance and must not be shared\n * between `RocksDatabase` instances. Each `RocksDatabase` claims its store on\n * construction (see `claim()`); passing a store that another `RocksDatabase`\n * already owns throws. (Sharing with the owning database's `Transaction`\n * instances is expected and allowed.)\n */\nexport class Store {\n\t/**\n\t * Whether a `RocksDatabase` has claimed this store. Durable across\n\t * close/reopen (unlike the handle's open state), so a store reused after its\n\t * owner temporarily closed is still recognized as in-use. See `claim()`.\n\t */\n\t#claimed: boolean = false;\n\n\t/**\n\t * The database instance.\n\t */\n\tdb: NativeDatabase;\n\n\t/**\n\t * The decoder instance. This is commonly the same as the `encoder`\n\t * instance.\n\t */\n\tdecoder: Encoder | null;\n\n\t/**\n\t * Whether the decoder copies the buffer when encoding values.\n\t */\n\tdecoderCopies: boolean = false;\n\n\t/**\n\t * The compression algorithm (or `{ algorithm, level }`) requested for this\n\t * store's column family. Normalized and applied when the database opens.\n\t */\n\tcompression?: CompressionOption;\n\n\t/**\n\t * Whether `compression` applies to every column family in the database rather than just this\n\t * store's. See `RocksDatabaseOptions.compressionForAllColumnFamilies`.\n\t */\n\tcompressionForAllColumnFamilies: boolean = false;\n\n\t/**\n\t * Whether to disable the write ahead log.\n\t */\n\tdisableWAL: boolean;\n\n\t/**\n\t * Whether to enable RocksDB statistics.\n\t */\n\tenableStats: boolean;\n\n\t/**\n\t * Reusable buffer for encoding values using `writeKey()` when the custom\n\t * encoder does not provide a `encode()` method.\n\t */\n\tencodeBuffer: BufferWithDataView;\n\n\t/**\n\t * The encoder instance.\n\t */\n\tencoder: Encoder | null;\n\n\t/**\n\t * The encoding used to encode values. Defaults to `'msgpack'` in\n\t * `RocksDatabase.open()`.\n\t */\n\tencoding: Encoding | null;\n\n\t/**\n\t * Encoder specific option used to signal that the data should be frozen.\n\t */\n\tfreezeData: boolean;\n\n\t/**\n\t * Reusable buffer for encoding keys.\n\t */\n\tkeyBuffer: BufferWithDataView;\n\n\t/**\n\t * The key encoding to use for keys. Defaults to `'ordered-binary'`.\n\t */\n\tkeyEncoding: KeyEncoding;\n\n\t/**\n\t * The maximum key size.\n\t */\n\tmaxKeySize: number;\n\n\t/**\n\t * The maximum number of table files RocksDB keeps open. `0` (the default)\n\t * derives a budget from the effective per-process open-file limit (an\n\t * eighth of the limit — several databases can share one process — clamped\n\t * to `[1024, 262144]`); `-1` holds every table file open (the RocksDB\n\t * default, which can exhaust the process file-descriptor limit when\n\t * compaction falls behind under sustained ingest); a positive `int32` is\n\t * an explicit cap.\n\t */\n\tmaxOpenFiles?: number;\n\n\t/**\n\t * The maximum number of memtables that can be queued per column family\n\t * before writes stall. Higher values absorb write bursts while flushes catch\n\t * up, at the cost of memory.\n\t */\n\tmaxWriteBufferNumber?: number;\n\n\t/**\n\t * The bytes of recent memtable history to retain in memory for transaction\n\t * conflict checking. `-1` derives the value from\n\t * `maxWriteBufferNumber * writeBufferSize`.\n\t */\n\tmaxWriteBufferSizeToMaintain?: number;\n\n\t/**\n\t * The total memtable budget in bytes across all column families. When the\n\t * sum of memtables reaches this size, RocksDB flushes the largest one. `0`\n\t * disables the global trigger so per-CF `writeBufferSize` drives flushing.\n\t */\n\tdbWriteBufferSize?: number;\n\n\t/**\n\t * The name of the store (e.g. the column family). Defaults to `'default'`.\n\t */\n\tname: string;\n\n\t/**\n\t * Whether to disable the block cache.\n\t */\n\tnoBlockCache?: boolean;\n\n\t/**\n\t * The number of threads to use for parallel operations. This is a RocksDB\n\t * option. When undefined, the native layer picks\n\t * `max(1, hardware_concurrency() / 2)`.\n\t */\n\tparallelismThreads?: number;\n\n\t/**\n\t * The path to the database.\n\t */\n\tpath: string;\n\n\t/**\n\t * Whether to use pessimistic locking for transactions. When `true`,\n\t * transactions will fail as soon as a conflict is detected. When `false`,\n\t * transactions will only fail when `commit()` is called.\n\t */\n\tpessimistic: boolean;\n\n\t/**\n\t * Whether the database is open in readonly mode. When `true`, write\n\t * operations will throw an error with code `ERR_DATABASE_READONLY`.\n\t */\n\treadOnly: boolean;\n\n\t/**\n\t * Encoder specific flag used to signal that the encoder should use a random\n\t * access structure.\n\t */\n\trandomAccessStructure: boolean;\n\n\t/**\n\t * The function used to encode keys.\n\t */\n\treadKey: ReadKeyFunction<Key>;\n\n\t/**\n\t * The key used to store shared structures.\n\t */\n\tsharedStructuresKey?: symbol;\n\n\t/**\n\t * The level of statistics to capture.\n\t */\n\tstatsLevel?: (typeof stats.StatsLevel)[keyof typeof stats.StatsLevel];\n\n\t/**\n\t * The threshold for the transaction log file's last modified time to be\n\t * older than the retention period before it is rotated to the next sequence\n\t * number. A threshold of 0 means ignore age check.\n\t */\n\ttransactionLogMaxAgeThreshold?: number;\n\n\t/**\n\t * The maximum size of a transaction log before it is rotated to the next\n\t * sequence number.\n\t */\n\ttransactionLogMaxSize?: number;\n\n\t/**\n\t * A string containing the amount of time or the number of milliseconds to\n\t * retain transaction logs before purging.\n\t *\n\t * @default '3d' (3 days)\n\t */\n\ttransactionLogRetention?: number | string;\n\n\t/**\n\t * The path to the transaction logs directory.\n\t */\n\ttransactionLogsPath?: string;\n\n\t/**\n\t * Whether this store's column family participates in the VerificationTable.\n\t */\n\tverificationTable?: boolean;\n\n\t/**\n\t * The per-column-family memtable size in bytes at which the memtable is\n\t * sealed and flushed.\n\t */\n\twriteBufferSize?: number;\n\n\t/**\n\t * The function used to encode keys using the shared `keyBuffer`.\n\t */\n\twriteKey: WriteKeyFunction;\n\n\t/**\n\t * Initializes the store with a new `NativeDatabase` instance.\n\t *\n\t * @param path - The path to the database.\n\t * @param options - The options for the store.\n\t */\n\tconstructor(path: string, options?: StoreOptions) {\n\t\tif (!path || typeof path !== 'string') {\n\t\t\tthrow new TypeError('Invalid database path');\n\t\t}\n\n\t\tif (options !== undefined && options !== null && typeof options !== 'object') {\n\t\t\tthrow new TypeError('Database options must be an object');\n\t\t}\n\n\t\tconst { keyEncoding, readKey, writeKey } = initKeyEncoder(\n\t\t\toptions?.keyEncoding,\n\t\t\toptions?.keyEncoder\n\t\t);\n\n\t\tthis.db = new NativeDatabase();\n\t\tthis.compression = options?.compression;\n\t\tthis.compressionForAllColumnFamilies = options?.compressionForAllColumnFamilies === true;\n\t\tthis.dbWriteBufferSize = options?.dbWriteBufferSize;\n\t\tthis.decoder = options?.decoder ?? null;\n\t\tthis.disableWAL = options?.disableWAL ?? false;\n\t\tthis.enableStats = options?.enableStats ?? false;\n\t\tthis.encodeBuffer = createFixedBuffer(SAVE_BUFFER_SIZE);\n\t\tthis.encoder = options?.encoder ?? null;\n\t\tthis.encoding = options?.encoding ?? null;\n\t\tthis.freezeData = options?.freezeData ?? false;\n\t\tthis.keyBuffer = KEY_BUFFER;\n\t\tthis.keyEncoding = keyEncoding;\n\t\tthis.maxKeySize = options?.maxKeySize ?? MAX_KEY_SIZE;\n\t\tthis.maxOpenFiles = options?.maxOpenFiles;\n\t\tthis.maxWriteBufferNumber = options?.maxWriteBufferNumber;\n\t\tthis.maxWriteBufferSizeToMaintain = options?.maxWriteBufferSizeToMaintain;\n\t\tthis.name = options?.name ?? 'default';\n\t\tthis.noBlockCache = options?.noBlockCache;\n\t\tthis.parallelismThreads = options?.parallelismThreads;\n\t\tthis.path = path;\n\t\tthis.pessimistic = options?.pessimistic ?? false;\n\t\tthis.readOnly = options?.readOnly ?? false;\n\t\tthis.randomAccessStructure = options?.randomAccessStructure ?? false;\n\t\tthis.readKey = readKey;\n\t\tthis.sharedStructuresKey = options?.sharedStructuresKey;\n\t\tthis.statsLevel = options?.statsLevel;\n\t\tthis.transactionLogMaxAgeThreshold = options?.transactionLogMaxAgeThreshold;\n\t\tthis.transactionLogMaxSize = options?.transactionLogMaxSize;\n\t\tthis.transactionLogRetention = options?.transactionLogRetention;\n\t\tthis.transactionLogsPath = options?.transactionLogsPath;\n\t\tthis.verificationTable = options?.verificationTable;\n\t\tthis.writeBufferSize = options?.writeBufferSize;\n\t\tthis.writeKey = writeKey;\n\t}\n\n\t/**\n\t * Closes the database.\n\t */\n\tclose(): void {\n\t\tthis.db.close();\n\t}\n\n\t/**\n\t * Claims this store for a `RocksDatabase`. A store is bound to a single\n\t * database instance, so claiming a store that another `RocksDatabase` has\n\t * already claimed throws. The claim is durable across close/reopen, so a\n\t * store reused after its owner temporarily closed still throws.\n\t */\n\tclaim(): void {\n\t\tif (this.#claimed) {\n\t\t\tthrow new Error('Store is already in use by another RocksDatabase instance');\n\t\t}\n\t\tthis.#claimed = true;\n\t}\n\n\t/**\n\t * Compacts the entire key range of the database asynchronously.\n\t * This triggers manual compaction which removes tombstones and reclaims space.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.compact();\n\t * ```\n\t */\n\tcompact(options?: CompactOptions): Promise<void> {\n\t\tlet startBuffer: Buffer | undefined;\n\t\tlet endBuffer: Buffer | undefined;\n\n\t\tif (options?.start !== undefined) {\n\t\t\tconst start = this.encodeKey(options.start);\n\t\t\tstartBuffer = Buffer.from(start.subarray(start.start, start.end));\n\t\t}\n\t\tif (options?.end !== undefined) {\n\t\t\tconst end = this.encodeKey(options.end);\n\t\t\tendBuffer = Buffer.from(end.subarray(end.start, end.end));\n\t\t}\n\n\t\treturn new Promise((resolve, reject) =>\n\t\t\tthis.db.compact(resolve, reject, startBuffer, endBuffer, options?.bottommost === true)\n\t\t);\n\t}\n\n\t/**\n\t * Creates a backup of the entire database (all column families) into the\n\t * given directory and resolves with the new backup id. Parent directories\n\t * are created as needed. See `backups` for restore and management.\n\t *\n\t * @example\n\t * ```typescript\n\t * const id = await db.backup('/path/to/backups');\n\t * ```\n\t */\n\tasync backup(backupDir: string, options?: BackupOptions): Promise<number>;\n\tasync backup(stream: WritableStream<Uint8Array>, options?: BackupStreamOptions): Promise<void>;\n\tasync backup(\n\t\ttarget: string | WritableStream<Uint8Array>,\n\t\toptions?: BackupOptions | BackupStreamOptions\n\t): Promise<number | void> {\n\t\t// Duck-type rather than `instanceof WritableStream` so a stream from a\n\t\t// different realm (or a polyfill) still routes to the streaming path.\n\t\tif (typeof target !== 'string' && typeof target?.getWriter === 'function') {\n\t\t\treturn backupToStream(this.db, target, options as BackupStreamOptions);\n\t\t}\n\t\t// Refuse to write backup files into the live database directory (or a\n\t\t// subdirectory of it), which would clobber RocksDB's own files.\n\t\tassertBackupDirOutsideDatabase(this.path, target as string);\n\t\t// The native side creates the directory (with missing parents) and holds\n\t\t// the on-disk single-writer lock for the duration of the backup — see\n\t\t// `runCreateBackup` in `src/binding/database/backup.cpp` and\n\t\t// `withBackupDirLock`. Rejects if the directory is already locked.\n\t\treturn new Promise((resolve, reject) =>\n\t\t\tthis.db.backup(resolve, reject, target as string, options as BackupOptions)\n\t\t);\n\t}\n\n\t/**\n\t * Compacts the entire key range of the database synchronously.\n\t * This triggers manual compaction which removes tombstones and reclaims space.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.compactSync();\n\t * ```\n\t */\n\tcompactSync(options?: CompactOptions): void {\n\t\tlet startBuffer: Buffer | undefined;\n\t\tlet endBuffer: Buffer | undefined;\n\n\t\tif (options?.start !== undefined) {\n\t\t\tconst start = this.encodeKey(options.start);\n\t\t\tstartBuffer = Buffer.from(start.subarray(start.start, start.end));\n\t\t}\n\t\tif (options?.end !== undefined) {\n\t\t\tconst end = this.encodeKey(options.end);\n\t\t\tendBuffer = Buffer.from(end.subarray(end.start, end.end));\n\t\t}\n\n\t\tthis.db.compactSync(startBuffer, endBuffer, options?.bottommost === true);\n\t}\n\n\t/**\n\t * Decodes a key from the database.\n\t *\n\t * @param key - The key to decode.\n\t * @returns The decoded key.\n\t */\n\tdecodeKey(key: Buffer): Key {\n\t\treturn this.readKey(key as BufferWithDataView, 0, key.length);\n\t}\n\n\t/**\n\t * Decodes a value from the database.\n\t *\n\t * @param value - The value to decode.\n\t * @returns The decoded value.\n\t */\n\tdecodeValue(value: BufferWithDataView): any {\n\t\tif (value?.length > 0 && typeof this.decoder?.decode === 'function') {\n\t\t\treturn this.decoder.decode(value, { end: value.end });\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Encodes a key for the database.\n\t *\n\t * @param key - The key to encode.\n\t * @returns The encoded key.\n\t */\n\tencodeKey(key: Key): BufferWithDataView {\n\t\tif (key === undefined) {\n\t\t\tthrow new Error('Key is required');\n\t\t}\n\n\t\tconst bytesWritten = this.writeKey(key, this.keyBuffer, 0);\n\t\tif (bytesWritten === 0) {\n\t\t\tthrow new Error('Zero length key is not allowed');\n\t\t}\n\n\t\tthis.keyBuffer.end = bytesWritten;\n\n\t\treturn this.keyBuffer;\n\t}\n\n\t/**\n\t * Encodes a value for the database.\n\t *\n\t * @param value - The value to encode.\n\t * @returns The encoded value.\n\t */\n\tencodeValue(value: any): BufferWithDataView | Uint8Array {\n\t\tif (value && value['\\x10binary-data\\x02']) {\n\t\t\treturn value['\\x10binary-data\\x02'];\n\t\t}\n\n\t\tif (typeof this.encoder?.encode === 'function') {\n\t\t\tif (this.encoder.copyBuffers) {\n\t\t\t\treturn this.encoder.encode(value, REUSE_BUFFER_MODE | RESET_BUFFER_MODE);\n\t\t\t}\n\n\t\t\tconst valueBuffer = this.encoder.encode(value);\n\t\t\tif (typeof valueBuffer === 'string') {\n\t\t\t\treturn Buffer.from(valueBuffer);\n\t\t\t}\n\t\t\treturn valueBuffer;\n\t\t}\n\n\t\tif (typeof value === 'string') {\n\t\t\treturn Buffer.from(value);\n\t\t}\n\n\t\tif (value instanceof Uint8Array) {\n\t\t\treturn value;\n\t\t}\n\n\t\tthrow new Error(`Invalid value put in database (${typeof value}), consider using an encoder`);\n\t}\n\n\tget(\n\t\tcontext: StoreContext,\n\t\tkey: Key,\n\t\talwaysCreateNewBuffer: boolean = false,\n\t\toptions?: StoreGetOptions\n\t): any | undefined {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\tlet flags = 0;\n\t\tif (alwaysCreateNewBuffer) {\n\t\t\t// used by getBinary to force a new safe long-lived buffer\n\t\t\tflags |= ALWAYS_CREATE_NEW_BUFFER_FLAG;\n\t\t}\n\t\tif (options?.populateVersion) {\n\t\t\tflags |= POPULATE_VERSION_FLAG;\n\t\t}\n\t\tconst txnId = this.getTxnId(options);\n\t\tconst expectedVersion = options?.expectedVersion;\n\t\t// getSync is the fast path, which can return immediately if the entry is in memory cache, but we want to fail otherwise\n\t\tconst result = context.getSync(\n\t\t\tkeyParam,\n\t\t\tflags | ONLY_IF_IN_MEMORY_CACHE_FLAG,\n\t\t\ttxnId,\n\t\t\texpectedVersion\n\t\t);\n\t\tif (typeof result === 'number') {\n\t\t\t// return a number indicates it is using the default buffer\n\t\t\tif (result === NOT_IN_MEMORY_CACHE_FLAG) {\n\t\t\t\t// is not in memory cache, use async get since this will involve disk access\n\t\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t\t// We still use the same shared buffer for the key, the native side will make a copy for the async task\n\t\t\t\t\tcontext.get(keyParam, resolve, reject, txnId, expectedVersion);\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (result === FRESH_VERSION_FLAG) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\t// continue with fast path\n\t\t\tVALUE_BUFFER.end = result;\n\t\t\treturn VALUE_BUFFER;\n\t\t} // else it is undefined or it is a new buffer\n\t\treturn result;\n\t}\n\n\tgetCount(context: StoreContext, options?: StoreRangeOptions): number {\n\t\toptions = { ...options };\n\n\t\tif (options?.start !== undefined) {\n\t\t\tconst start = this.encodeKey(options.start);\n\t\t\toptions.start = Buffer.from(start.subarray(start.start, start.end));\n\t\t}\n\n\t\tif (options?.end !== undefined) {\n\t\t\tconst end = this.encodeKey(options.end);\n\t\t\toptions.end = Buffer.from(end.subarray(end.start, end.end));\n\t\t}\n\n\t\treturn context.getCount(options, this.getTxnId(options));\n\t}\n\n\tgetKeys(context: StoreContext, options?: StoreIteratorOptions): any | undefined {\n\t\treturn this.getRange(context, { ...options, values: false }).map((item) => item.key);\n\t}\n\n\tgetKeysCount(context: StoreContext, options?: StoreRangeOptions): number {\n\t\treturn this.getCount(context, options);\n\t}\n\n\tgetRange(\n\t\tcontext: StoreContext,\n\t\toptions?: StoreIteratorOptions\n\t): ExtendedIterable<DBIteratorValue<any>> {\n\t\tif (!this.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\t// Resolve start/end keys, honoring the `key` shortcut for single-key\n\t\t// matches and swapping start/end when iterating in reverse.\n\t\tlet startUnencoded = options?.key ?? options?.start;\n\t\tlet endUnencoded = options?.key ?? options?.end;\n\n\t\tconst includeValues = options?.values ?? true;\n\t\tconst reverse = options?.reverse ?? false;\n\n\t\tlet exclusiveStart = options?.exclusiveStart ?? false;\n\t\tlet inclusiveEnd = options?.inclusiveEnd ?? false;\n\t\tif (options?.key !== undefined) {\n\t\t\tinclusiveEnd = true;\n\t\t}\n\n\t\tif (reverse) {\n\t\t\tconst tmp = startUnencoded;\n\t\t\tstartUnencoded = endUnencoded;\n\t\t\tendUnencoded = tmp;\n\t\t\t// preserve previous default behavior: reverse iteration treats\n\t\t\t// missing exclusiveStart/inclusiveEnd as `true`\n\t\t\texclusiveStart = options?.exclusiveStart ?? true;\n\t\t\tinclusiveEnd = options?.inclusiveEnd ?? true;\n\t\t}\n\n\t\t// Encode both keys back-to-back into the shared key buffer. Each key\n\t\t// is identified to the native side by its (start, end) offsets.\n\t\tconst keyBuffer = this.keyBuffer;\n\t\tlet startKeyEnd = 0;\n\t\tlet endKeyStart = 0;\n\t\tlet endKeyEnd = 0;\n\n\t\tif (startUnencoded !== undefined) {\n\t\t\tstartKeyEnd = this.writeKey(startUnencoded, keyBuffer, 0);\n\t\t\tif (startKeyEnd === 0) {\n\t\t\t\tthrow new Error('Zero length key is not allowed');\n\t\t\t}\n\t\t}\n\n\t\tif (endUnencoded !== undefined) {\n\t\t\tif (endUnencoded === startUnencoded) {\n\t\t\t\t// `key` shortcut: reuse the encoded start key bytes\n\t\t\t\tendKeyStart = 0;\n\t\t\t\tendKeyEnd = startKeyEnd;\n\t\t\t} else {\n\t\t\t\tendKeyStart = startKeyEnd;\n\t\t\t\tendKeyEnd = this.writeKey(endUnencoded, keyBuffer, endKeyStart);\n\t\t\t\tif (endKeyEnd === endKeyStart) {\n\t\t\t\t\tthrow new Error('Zero length key is not allowed');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet flags = 0;\n\t\tif (reverse) flags |= ITERATOR_REVERSE_FLAG;\n\t\tif (exclusiveStart) flags |= ITERATOR_EXCLUSIVE_START_FLAG;\n\t\tif (inclusiveEnd) flags |= ITERATOR_INCLUSIVE_END_FLAG;\n\t\tif (includeValues) flags |= ITERATOR_INCLUDE_VALUES_FLAG;\n\t\tif (includeValues && !this.decoderCopies) {\n\t\t\tflags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;\n\t\t}\n\t\t// Tell the native constructor whether `context` is a Transaction (vs.\n\t\t// the database) so it can skip a napi_instanceof check. The store\n\t\t// holds the canonical NativeDatabase reference, so identity comparison\n\t\t// is sufficient.\n\t\tif (context !== this.db) {\n\t\t\tflags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;\n\t\t}\n\n\t\t// Only pass the advanced ReadOptions object on the rare path where any\n\t\t// of the underlying RocksDB iterator options are actually overridden.\n\t\tconst advancedOptions =\n\t\t\toptions !== undefined &&\n\t\t\t(options.adaptiveReadahead !== undefined ||\n\t\t\t\toptions.asyncIO !== undefined ||\n\t\t\t\toptions.autoReadaheadSize !== undefined ||\n\t\t\t\toptions.backgroundPurgeOnIteratorCleanup !== undefined ||\n\t\t\t\toptions.fillCache !== undefined ||\n\t\t\t\toptions.readaheadSize !== undefined ||\n\t\t\t\toptions.tailing !== undefined)\n\t\t\t\t? options\n\t\t\t\t: undefined;\n\n\t\treturn new ExtendedIterable(\n\t\t\t// @ts-expect-error ExtendedIterable v1 constructor type definition is incorrect\n\t\t\tnew DBIterator(\n\t\t\t\tnew NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions),\n\t\t\t\tthis,\n\t\t\t\tincludeValues,\n\t\t\t\toptions?.limit\n\t\t\t)\n\t\t);\n\t}\n\n\tgetSync(\n\t\tcontext: StoreContext,\n\t\tkey: Key,\n\t\talwaysCreateNewBuffer: boolean = false,\n\t\toptions?: StoreGetOptions\n\t): any | undefined {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\tlet flags = 0;\n\t\tif (alwaysCreateNewBuffer) {\n\t\t\tflags |= ALWAYS_CREATE_NEW_BUFFER_FLAG;\n\t\t}\n\t\tif (options?.populateVersion) {\n\t\t\tflags |= POPULATE_VERSION_FLAG;\n\t\t}\n\t\t// we are using the shared buffer for keys, so we just pass in the key ending point (much faster than passing in a buffer)\n\t\tconst result = context.getSync(\n\t\t\tkeyParam,\n\t\t\tflags,\n\t\t\tthis.getTxnId(options),\n\t\t\toptions?.expectedVersion\n\t\t);\n\t\tif (typeof result === 'number') {\n\t\t\tif (result === FRESH_VERSION_FLAG) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\t// return a number indicates it is using the default buffer\n\t\t\tVALUE_BUFFER.end = result;\n\t\t\treturn VALUE_BUFFER;\n\t\t} // else it is undefined or it is a new buffer\n\t\treturn result;\n\t}\n\n\t/**\n\t * Checks if the data method options object contains a transaction ID and\n\t * returns it.\n\t */\n\tgetTxnId(options?: DBITransactional | unknown): number | undefined {\n\t\tlet txnId: number | undefined;\n\t\tif (!this.readOnly && (options as DBITransactional)?.transaction) {\n\t\t\ttxnId = (options as DBITransactional).transaction!.id;\n\t\t\tif (txnId === undefined) {\n\t\t\t\tthrow new TypeError('Invalid transaction');\n\t\t\t}\n\t\t}\n\t\treturn txnId;\n\t}\n\n\t/**\n\t * Gets or creates a buffer that can be shared across worker threads.\n\t *\n\t * @param key - The key to get or create the buffer for.\n\t * @param defaultBuffer - The default buffer to copy and use if the buffer\n\t * does not exist.\n\t * @param [options] - The options for the buffer.\n\t * @param [options.callback] - A optional callback is called when `notify()`\n\t * on the returned buffer is called.\n\t * @returns An `ArrayBuffer` that is internally backed by a rocksdb-js\n\t * managed buffer. The buffer also has `notify()` and `cancel()` methods\n\t * that can be used to notify the specified `options.callback`.\n\t */\n\tgetUserSharedBuffer(\n\t\tkey: Key,\n\t\tdefaultBuffer: ArrayBuffer,\n\t\toptions?: UserSharedBufferOptions\n\t): ArrayBufferWithNotify {\n\t\tconst encodedKey = this.encodeKey(key);\n\n\t\tif (options !== undefined && typeof options !== 'object') {\n\t\t\tthrow new TypeError('Options must be an object');\n\t\t}\n\n\t\tconst buffer = this.db.getUserSharedBuffer(\n\t\t\tencodedKey,\n\t\t\tdefaultBuffer,\n\t\t\toptions?.callback\n\t\t) as ArrayBufferWithNotify;\n\n\t\t// note: the notification methods need to re-encode the key because\n\t\t// encodeKey() uses a shared key buffer\n\t\tbuffer.notify = (...args: any[]) => {\n\t\t\treturn this.db.notify(this.encodeKey(key), args);\n\t\t};\n\t\tbuffer.cancel = () => {\n\t\t\tif (options?.callback) {\n\t\t\t\tthis.db.removeListener(this.encodeKey(key), options.callback);\n\t\t\t}\n\t\t};\n\t\treturn buffer;\n\t}\n\n\t/**\n\t * Checks if a lock exists.\n\t * @param key The lock key.\n\t * @returns `true` if the lock exists, `false` otherwise\n\t */\n\thasLock(key: Key): boolean {\n\t\treturn this.db.hasLock(this.encodeKey(key));\n\t}\n\n\t/**\n\t * Checks if the database is open.\n\t *\n\t * @returns `true` if the database is open, `false` otherwise.\n\t */\n\tisOpen(): boolean {\n\t\treturn this.db.opened;\n\t}\n\n\t/**\n\t * Lists all transaction log names.\n\t *\n\t * @returns an array of transaction log names.\n\t */\n\tlistLogs(): string[] {\n\t\treturn this.db.listLogs();\n\t}\n\n\t/**\n\t * Opens the database. This must be called before any database operations\n\t * are performed.\n\t */\n\topen(): boolean {\n\t\tif (this.db.opened) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst { compression, compressionLevel } = normalizeCompression(this.compression);\n\n\t\tthis.db.open(this.path, {\n\t\t\tcompression,\n\t\t\tcompressionLevel,\n\t\t\tcompressionForAllColumnFamilies: this.compressionForAllColumnFamilies,\n\t\t\tdbWriteBufferSize: this.dbWriteBufferSize,\n\t\t\tdisableWAL: this.disableWAL,\n\t\t\tenableStats: this.enableStats,\n\t\t\tmaxOpenFiles: this.maxOpenFiles,\n\t\t\tmaxWriteBufferNumber: this.maxWriteBufferNumber,\n\t\t\tmaxWriteBufferSizeToMaintain: this.maxWriteBufferSizeToMaintain,\n\t\t\tmode: this.pessimistic ? 'pessimistic' : 'optimistic',\n\t\t\tname: this.name,\n\t\t\tnoBlockCache: this.noBlockCache,\n\t\t\tparallelismThreads: this.parallelismThreads,\n\t\t\treadOnly: this.readOnly,\n\t\t\tstatsLevel: this.statsLevel,\n\t\t\ttransactionLogMaxAgeThreshold: this.transactionLogMaxAgeThreshold,\n\t\t\ttransactionLogMaxSize: this.transactionLogMaxSize,\n\t\t\ttransactionLogRetentionMs: this.transactionLogRetention\n\t\t\t\t? parseDuration(this.transactionLogRetention)\n\t\t\t\t: undefined,\n\t\t\ttransactionLogsPath: this.transactionLogsPath,\n\t\t\tverificationTable: this.verificationTable,\n\t\t\twriteBufferSize: this.writeBufferSize,\n\t\t});\n\n\t\treturn false;\n\t}\n\n\tputSync(context: StoreContext, key: Key, value: any, options?: StorePutOptions): void {\n\t\tif (!this.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\t// IMPORTANT!\n\t\t// We MUST encode the value before the key because if the `sharedStructuresKey`\n\t\t// is set, it will be used by `getStructures()` and `saveStructures()` which in\n\t\t// turn will encode the `sharedStructuresKey` into the shared `keyBuffer`\n\t\t// overwriting this method's encoded key!\n\t\tconst valueBuffer = this.encodeValue(value);\n\n\t\tcontext.putSync(this.encodeKey(key), valueBuffer, this.getTxnId(options));\n\t}\n\n\tremoveSync(context: StoreContext, key: Key, options?: StoreRemoveOptions): void {\n\t\tif (!this.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\tcontext.removeSync(this.encodeKey(key), this.getTxnId(options));\n\t}\n\n\t/**\n\t * Attempts to acquire a lock for a given key. If the lock is available,\n\t * the function returns `true` and the optional callback is never called.\n\t * If the lock is not available, the function returns `false` and the\n\t * callback is queued until the lock is released.\n\t *\n\t * @param key - The key to lock.\n\t * @param onUnlocked - A callback to call when the lock is released.\n\t * @returns `true` if the lock was acquired, `false` otherwise.\n\t */\n\ttryLock(key: Key, onUnlocked?: () => void): boolean {\n\t\tif (onUnlocked !== undefined && typeof onUnlocked !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\treturn this.db.tryLock(this.encodeKey(key), onUnlocked);\n\t}\n\n\t/**\n\t * Releases the lock on the given key and calls any queued `onUnlocked`\n\t * callback handlers.\n\t *\n\t * @param key - The key to unlock.\n\t */\n\tunlock(key: Key): void {\n\t\treturn this.db.unlock(this.encodeKey(key));\n\t}\n\n\t/**\n\t * Gets or creates a transaction log instance.\n\t *\n\t * @param context - The context to use for the transaction log.\n\t * @param name - The name of the transaction log.\n\t * @returns The transaction log.\n\t */\n\tuseLog(context: StoreContext, name: string | number): TransactionLog {\n\t\tif (typeof name !== 'string' && typeof name !== 'number') {\n\t\t\tthrow new TypeError('Log name must be a string or number');\n\t\t}\n\t\tif (typeof name === 'string' && /[\\t\\n\\r\\\\/]/.test(name)) {\n\t\t\tthrow new Error(`Invalid transaction log name \"${name}\"`);\n\t\t}\n\t\treturn context.useLog(String(name));\n\t}\n\n\t/**\n\t * Checks the process-global verification table for a fresh version match\n\t * on `key`. Returns `true` when the table currently records `version` for\n\t * this database+column-family. Provides a fast cache-freshness check\n\t * before falling back to a full read.\n\t */\n\tverifyVersion(key: Key, version: number): boolean {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\treturn this.db.verifyVersion(keyParam, version);\n\t}\n\n\t/**\n\t * Seeds the verification-table slot for `key` with `version`. Has no\n\t * effect if the slot is currently lock-tagged or the table is disabled.\n\t * Useful after a full read where the caller already knows the version.\n\t */\n\tpopulateVersion(key: Key, version: number): void {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\tthis.db.populateVersion(keyParam, version);\n\t}\n\n\t/**\n\t * Acquires a lock on the given key and calls the callback.\n\t *\n\t * @param key - The key to lock.\n\t * @param callback - The callback to call when the lock is acquired.\n\t * @returns A promise that resolves when the lock is acquired.\n\t */\n\twithLock(key: Key, callback: () => void | Promise<void>): Promise<void> {\n\t\tif (typeof callback !== 'function') {\n\t\t\treturn Promise.reject(new TypeError('Callback must be a function'));\n\t\t}\n\n\t\treturn this.db.withLock(this.encodeKey(key), callback);\n\t}\n}\n\n/**\n * Ensure that they key has been copied into our shared buffer, and return the ending position\n * @param keyBuffer\n */\nfunction getKeyParam(keyBuffer: BufferWithDataView): number | Buffer {\n\tif (keyBuffer.buffer === KEY_BUFFER.buffer) {\n\t\tif (keyBuffer.end >= 0) {\n\t\t\treturn keyBuffer.end;\n\t\t}\n\t\tif (keyBuffer.byteOffset === 0) {\n\t\t\treturn keyBuffer.byteLength;\n\t\t}\n\t}\n\tif (keyBuffer.length > KEY_BUFFER.length) {\n\t\t// for larger key buffers, we pass it straight in\n\t\treturn keyBuffer;\n\t}\n\tKEY_BUFFER.set(keyBuffer);\n\treturn keyBuffer.length;\n}\n\nexport interface GetOptions {\n\t/**\n\t * When set, the native layer checks the verification table before reading.\n\t * If the slot holds this version, returns `FRESH_VERSION_FLAG` immediately\n\t * (the cached value is still valid). After a DB read, also seeds the slot\n\t * with the version extracted from the value.\n\t */\n\texpectedVersion?: number;\n\n\t/**\n\t * When `true`, after a DB read the native layer automatically seeds the\n\t * verification-table slot with the version extracted from the value.\n\t * Eliminates the need for a separate `populateVersion` call on cold reads.\n\t *\n\t * @default false\n\t */\n\tpopulateVersion?: boolean;\n\n\t/**\n\t * Whether to skip decoding the value.\n\t *\n\t * @default false\n\t */\n\tskipDecode?: boolean;\n}\n\nexport interface PutOptions {\n\tappend?: boolean;\n\tinstructedWrite?: boolean;\n\tnoDupData?: boolean;\n\tnoOverwrite?: boolean;\n}\n","import { DBI } from './dbi';\nimport { constants, NativeTransaction, type NativeTransactionOptions } from './load-binding.js';\nimport { Store } from './store.js';\n\n/**\n * Sentinel value returned by `commit()` when `coordinatedRetry: true` and the\n * transaction encountered an IsBusy conflict. The native layer parks on VT\n * slots and resolves only after the conflicting transaction releases its write\n * intent, so callers should retry immediately without any backoff delay.\n */\nexport const RETRY_NOW: number = constants.RETRY_NOW_VALUE;\n\nexport class TransactionAlreadyAbortedError extends Error {\n\treadonly code = 'ERR_ALREADY_ABORTED';\n}\n\n/**\n * Base for commit conflicts the native layer has already recovered from by resetting the\n * transaction in place (fresh RocksDB snapshot; `committedPosition` preserved, so a staged\n * transaction-log batch stays write-once): the caller should re-run the transaction body\n * and retry the commit — the handling is identical for every subclass. `hasLog` reports\n * whether the transaction wrote to a transaction log (drives the default retry decision).\n *\n * {@link TransactionAbandonedError} shares this field shape but deliberately does NOT\n * extend this class — an abandoned transaction is not retryable, and retryability is the\n * boundary this hierarchy expresses.\n */\nexport class TransactionRetryableError extends Error {\n\treadonly hasLog: boolean;\n\treadonly txn: Transaction;\n\n\tconstructor(error: Error, txn: Transaction) {\n\t\tsuper(error.message);\n\t\tthis.hasLog = (error as Error & { hasLog?: boolean }).hasLog ?? false;\n\t\tthis.txn = txn;\n\t}\n}\n\n/**\n * An optimistic commit detected a write conflict with a concurrently committed\n * transaction (RocksDB `Busy`).\n */\nexport class TransactionIsBusyError extends TransactionRetryableError {\n\treadonly code = 'ERR_BUSY';\n}\n\n/**\n * An optimistic commit could not be validated: the transaction's snapshot was stranded\n * outside the memtable window (its sequence history was flushed away — RocksDB\n * `TryAgain`), so the conflict check had nothing to validate against.\n */\nexport class TransactionTryAgainError extends TransactionRetryableError {\n\treadonly code = 'ERR_TRY_AGAIN';\n}\n\nexport class TransactionAbandonedError extends Error {\n\treadonly code = 'ERR_TRANSACTION_ABANDONED';\n\treadonly hasLog: boolean;\n\treadonly txn: Transaction;\n\n\tconstructor(error: Error, txn: Transaction) {\n\t\tsuper(error.message);\n\t\tthis.hasLog = (error as Error & { hasLog?: boolean }).hasLog ?? false;\n\t\tthis.txn = txn;\n\t}\n}\n\n/**\n * Provides transaction level operations to a transaction callback.\n */\nexport class Transaction extends DBI {\n\t#txn: NativeTransaction;\n\n\t/**\n\t * Create a new transaction.\n\t *\n\t * @param store - The base store interface for this transaction.\n\t * @param options - The options for the transaction.\n\t */\n\tconstructor(store: Store, options?: NativeTransactionOptions) {\n\t\tif (store.readOnly) {\n\t\t\tsuper(store);\n\t\t\tthis.#txn = { id: 0 } as NativeTransaction;\n\t\t\tthis.abandonWrites = this.abort = this.commitSync = this.setTimestamp = () => {};\n\t\t\tthis.commit = async () => {};\n\t\t\tthis.getTimestamp = () => 0;\n\t\t} else {\n\t\t\tconst txn = new NativeTransaction(store.db, options);\n\t\t\tsuper(store, txn);\n\t\t\tthis.#txn = txn;\n\t\t}\n\t}\n\n\t/**\n\t * Release the staged writes' verification-table write intents without\n\t * closing the transaction, barring any later commit or write. For a\n\t * transaction kept open only for its outstanding read iterators after the\n\t * writes were replayed onto another transaction: otherwise other writers'\n\t * coordinated-retry commits park on those intents until it is aborted.\n\t * Reads keep working, including read-your-own-writes.\n\t */\n\tabandonWrites(): void {\n\t\tthis.#txn.abandonWrites();\n\t}\n\n\t/**\n\t * Abort the transaction.\n\t */\n\tabort(): void {\n\t\ttry {\n\t\t\tthis.#txn.abort();\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_TRANSACTION_ABANDONED') {\n\t\t\t\tthrow new TransactionAbandonedError(err, this);\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t/**\n\t * Commit the transaction.\n\t *\n\t * Returns `RETRY_NOW` when `coordinatedRetry: true` and an IsBusy conflict\n\t * was detected. The caller should retry the transaction body immediately.\n\t */\n\tasync commit(): Promise<typeof RETRY_NOW | void> {\n\t\ttry {\n\t\t\tconst result = await new Promise<number | void>((resolve, reject) => {\n\t\t\t\tthis.notify('beforecommit');\n\t\t\t\tthis.#txn.commit(resolve, reject);\n\t\t\t});\n\t\t\tif (result === RETRY_NOW) {\n\t\t\t\treturn RETRY_NOW;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow this.#handleCommitError(err);\n\t\t} finally {\n\t\t\tthis.notify('aftercommit', { next: null, last: null, txnId: this.#txn.id });\n\t\t}\n\t}\n\n\t/**\n\t * Commit the transaction synchronously.\n\t */\n\tcommitSync(): void {\n\t\ttry {\n\t\t\tthis.notify('beforecommit');\n\t\t\tthis.#txn.commitSync();\n\t\t} catch (err) {\n\t\t\tthrow this.#handleCommitError(err);\n\t\t} finally {\n\t\t\tthis.notify('aftercommit', { next: null, last: null, txnId: this.#txn.id });\n\t\t}\n\t}\n\n\t/**\n\t * Detect if error is an already aborted or busy error and return the appropriate error class.\n\t *\n\t * @param err - The error to check.\n\t * @returns The specialized error.\n\t */\n\t#handleCommitError(err: unknown): Error {\n\t\tif (err instanceof Error && 'code' in err) {\n\t\t\tif (err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\treturn new TransactionAlreadyAbortedError(err.message);\n\t\t\t}\n\t\t\tif (err.code === 'ERR_BUSY') {\n\t\t\t\treturn new TransactionIsBusyError(err, this);\n\t\t\t}\n\t\t\tif (err.code === 'ERR_TRY_AGAIN') {\n\t\t\t\treturn new TransactionTryAgainError(err, this);\n\t\t\t}\n\t\t}\n\t\treturn err as Error;\n\t}\n\n\t/**\n\t * Returns the transaction start timestamp in seconds. Defaults to the time at which\n\t * the transaction was created.\n\t *\n\t * @returns The transaction start timestamp in seconds.\n\t */\n\tgetTimestamp(): number {\n\t\treturn this.#txn.getTimestamp();\n\t}\n\n\t/**\n\t * Get the transaction id.\n\t */\n\tget id(): number {\n\t\treturn this.#txn.id;\n\t}\n\n\t/**\n\t * Set the transaction start timestamp in seconds.\n\t *\n\t * @param timestamp - The timestamp to set in seconds.\n\t */\n\tsetTimestamp(timestamp?: number): void {\n\t\tthis.#txn.setTimestamp(timestamp);\n\t}\n}\n","import type { BackupStreamOptions } from './backup-stream.js';\nimport type { BackupOptions } from './backup.js';\nimport { DBI, type DBITransactional } from './dbi.js';\nimport type { BufferWithDataView, Encoder, EncoderFunction, Key } from './encoding.js';\nimport {\n\taddGlobalListener,\n\tconfig,\n\tglobalListenerCount,\n\tglobalNotify,\n\tremoveGlobalListener,\n\ttype PurgedLog,\n\ttype PurgeLogsOptions,\n\ttype RocksDatabaseConfig,\n\ttype NativeTransactionOptions,\n} from './load-binding.js';\nimport type { StatsAll, StatsDefault, StatsValue } from './stats.js';\nimport {\n\ttype ArrayBufferWithNotify,\n\tCompactOptions,\n\ttype CompressionInfo,\n\tITERATOR_STATE_BUFFER,\n\tKEY_BUFFER,\n\tStore,\n\ttype StoreOptions,\n\ttype UserSharedBufferOptions,\n\tVALUE_BUFFER,\n} from './store.js';\nimport {\n\tRETRY_NOW,\n\tTransaction,\n\tTransactionAbandonedError,\n\tTransactionAlreadyAbortedError,\n\tTransactionRetryableError,\n} from './transaction.js';\nimport { Encoder as MsgpackEncoder } from 'msgpackr';\nimport { existsSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport * as orderedBinary from 'ordered-binary';\n\nexport type TransactionCallback<T> = (txn: Transaction, attempt: number) => T | PromiseLike<T>;\n\nexport interface RocksDatabaseOptions extends StoreOptions {\n\t/**\n\t * The column family name.\n\t *\n\t * @default 'default'\n\t */\n\tname?: string;\n}\n\nexport interface TransactionOptions extends NativeTransactionOptions {\n\t/**\n\t * The maximum number of times to retry the transaction.\n\t *\n\t * @default 3\n\t */\n\tmaxRetries?: number;\n\n\t/**\n\t * Whether to retry the transaction if it fails with `IsBusy`.\n\t *\n\t * @default `true` when the transaction is bound to a transaction log, otherwise `false`\n\t */\n\tretryOnBusy?: boolean;\n}\n\nexport type RocksDBStat = StatsValue;\nexport type RocksDBStats = StatsDefault | StatsAll;\n\n/**\n * The main class for interacting with a RocksDB database.\n *\n * Before using this class, you must open the database first.\n *\n * @example\n * ```typescript\n * const db = RocksDatabase.open('/path/to/database');\n * await db.put('key', 'value');\n * const value = await db.get('key');\n * db.close();\n * ```\n */\nexport class RocksDatabase extends DBI<DBITransactional> {\n\t/**\n\t * The name of the database.\n\t */\n\t#name: string;\n\n\tconstructor(pathOrStore: string | Store, options?: RocksDatabaseOptions) {\n\t\t// A store is bound to a single RocksDatabase instance. Each database claims\n\t\t// its store on construction; passing a store another database already owns\n\t\t// throws (see Store#claim).\n\t\tlet store: Store;\n\t\tif (typeof pathOrStore === 'string') {\n\t\t\tstore = new Store(pathOrStore, options);\n\t\t} else if (pathOrStore instanceof Store) {\n\t\t\tstore = pathOrStore;\n\t\t} else {\n\t\t\tthrow new TypeError('Invalid database path or store');\n\t\t}\n\t\tstore.claim();\n\t\tsuper(store);\n\t\tthis.#name = options?.name ?? 'default';\n\t}\n\n\t/**\n\t * Removes all data from the database asynchronously.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.clear();\n\t * ```\n\t */\n\tclear(): Promise<void> {\n\t\tif (this.store.encoder?.structures !== undefined) {\n\t\t\tthis.store.encoder.structures = [];\n\t\t}\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.store.db.clear(resolve, reject);\n\t\t});\n\t}\n\n\t/**\n\t * Removes all entries from the database synchronously.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.clearSync();\n\t * ```\n\t */\n\tclearSync(): void {\n\t\tif (this.store.encoder?.structures !== undefined) {\n\t\t\tthis.store.encoder.structures = [];\n\t\t}\n\n\t\tthis.store.db.clearSync();\n\t}\n\n\t/**\n\t * Closes the database.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.close();\n\t * ```\n\t */\n\tclose(): void {\n\t\tthis.store.close();\n\t}\n\n\t/**\n\t * Compacts the entire key range of the database asynchronously.\n\t * This triggers manual compaction which removes tombstones and reclaims space.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.compact();\n\t * ```\n\t */\n\tcompact(options?: CompactOptions): Promise<void> {\n\t\treturn this.store.compact(options);\n\t}\n\n\t/**\n\t * Creates a backup of the entire database (all column families) into the\n\t * given directory, creating parent directories as needed, and resolves with\n\t * the new backup id. Use the `backups` namespace to restore, list, delete,\n\t * purge, or verify backups.\n\t *\n\t * When the database was opened with `disableWAL`, the memtable is flushed\n\t * before the backup by default so unflushed data is not lost.\n\t *\n\t * @example\n\t * ```typescript\n\t * import { backups } from '@harperfast/rocksdb-js';\n\t *\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const id = await db.backup('/path/to/backups');\n\t * ```\n\t */\n\tbackup(backupDir: string, options?: BackupOptions): Promise<number>;\n\t/**\n\t * Streams a consistent snapshot of the entire database to a `WritableStream`\n\t * as a tar archive, with no intermediate copy written to disk. Resolves once\n\t * the stream has been fully written and closed.\n\t *\n\t * Backpressure is honored end to end, so a slow consumer (e.g. a network or\n\t * S3 upload) paces the backup rather than buffering it in memory. The archive\n\t * unpacks with any tar tool into a directory that opens as a RocksDB database.\n\t *\n\t * @example\n\t * ```typescript\n\t * const file = await fetch(uploadUrl, { method: 'PUT', body: stream });\n\t * await db.backup(stream); // `stream` is the request's WritableStream\n\t * ```\n\t */\n\tbackup(stream: WritableStream<Uint8Array>, options?: BackupStreamOptions): Promise<void>;\n\tbackup(\n\t\ttarget: string | WritableStream<Uint8Array>,\n\t\toptions?: BackupOptions | BackupStreamOptions\n\t): Promise<number | void> {\n\t\tif (typeof target === 'string') {\n\t\t\treturn this.store.backup(target, options as BackupOptions);\n\t\t}\n\t\treturn this.store.backup(target, options as BackupStreamOptions);\n\t}\n\n\t/**\n\t * Creates a hardlinked, point-in-time, fully independent copy of the entire\n\t * database (all column families) at `targetPath` and resolves once written.\n\t *\n\t * Unlike a backup, a checkpoint is a normal, writable sibling database: open\n\t * it with {@link RocksDatabase.open} and it diverges independently from the\n\t * source. SST and blob files are hardlinked when `targetPath` is on the same\n\t * filesystem as the database and copied otherwise (other files such as the\n\t * MANIFEST are always copied), so the operation is near-instant on the same\n\t * filesystem. The memtable is flushed so the checkpoint includes the latest\n\t * writes even when the WAL is disabled.\n\t *\n\t * Parent directories are created as needed. `targetPath` itself must not\n\t * already exist (RocksDB creates the checkpoint directory) and rejects with\n\t * `Create checkpoint failed: target path exists` if it does. The caller is\n\t * responsible for eventual cleanup of the directory.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.createCheckpoint('/path/to/checkpoint');\n\t * const branch = RocksDatabase.open('/path/to/checkpoint');\n\t * ```\n\t */\n\tcreateCheckpoint(targetPath: string): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tif (existsSync(targetPath)) {\n\t\t\t\treject(new Error('Create checkpoint failed: target path exists'));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Create parent directories as needed (a throw here rejects the promise),\n\t\t\t// then hand off to the native worker synchronously so it registers its\n\t\t\t// in-flight operation before this call returns.\n\t\t\tmkdirSync(dirname(targetPath), { recursive: true });\n\t\t\tthis.store.db.createCheckpoint(resolve, reject, targetPath);\n\t\t});\n\t}\n\n\t/**\n\t * Compacts the entire key range of the database synchronously.\n\t * This triggers manual compaction which removes tombstones and reclaims space.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.compactSync();\n\t * ```\n\t */\n\tcompactSync(options?: CompactOptions): void {\n\t\treturn this.store.compactSync(options);\n\t}\n\n\t/**\n\t * Returns the list of column families in the RocksDB database.\n\t */\n\tget columns(): string[] {\n\t\treturn this.store.db.columns;\n\t}\n\n\t/**\n\t * The compression currently in effect for this database's column family, read\n\t * live from RocksDB, as `{ algorithm, level? }`. `algorithm` is a friendly\n\t * name (e.g. `'lz4'`, `'zstd'`, `'none'`); `level` is present only when a\n\t * non-default compression level is set. The database must be open. Defaults to\n\t * LZ4 when the native build supports it.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/db', { compression: { algorithm: 'zstd', level: 3 } });\n\t * db.compression; // { algorithm: 'zstd', level: 3 }\n\t * ```\n\t */\n\tget compression(): CompressionInfo {\n\t\treturn this.store.db.getCompression() as CompressionInfo;\n\t}\n\n\t/**\n\t * Set global database settings.\n\t *\n\t * @param options - The options for the database.\n\t *\n\t * @example\n\t * ```typescript\n\t * RocksDatabase.config({ blockCacheSize: 1024 * 1024 });\n\t * ```\n\t */\n\tstatic config(options: RocksDatabaseConfig): void {\n\t\tconfig(options);\n\t}\n\n\t/**\n\t * Registers a process-wide event listener. Internal events emitted by the\n\t * native binding use namespaced keys (e.g. `'transactionLog:warning'`).\n\t *\n\t * Listeners are not tied to any specific database — they fire for every\n\t * matching event emitted in this process.\n\t *\n\t * @example\n\t * ```typescript\n\t * RocksDatabase.on('transactionLog:warning', (warning) => {\n\t * console.warn(warning);\n\t * });\n\t * ```\n\t */\n\tstatic on(event: string, callback: (...args: any[]) => void): void {\n\t\taddGlobalListener(event, callback);\n\t}\n\n\t/**\n\t * Alias for {@link RocksDatabase.on}, mirroring the Node `EventEmitter` API.\n\t */\n\tstatic addListener(event: string, callback: (...args: any[]) => void): void {\n\t\taddGlobalListener(event, callback);\n\t}\n\n\t/**\n\t * Removes a previously-registered process-wide event listener. The\n\t * callback identity must match the one passed to {@link RocksDatabase.on}.\n\t *\n\t * @returns `true` if a matching listener was removed.\n\t */\n\tstatic off(event: string, callback: (...args: any[]) => void): boolean {\n\t\treturn removeGlobalListener(event, callback);\n\t}\n\n\t/**\n\t * Alias for {@link RocksDatabase.off}, mirroring the Node `EventEmitter` API.\n\t */\n\tstatic removeListener(event: string, callback: (...args: any[]) => void): boolean {\n\t\treturn removeGlobalListener(event, callback);\n\t}\n\n\t/**\n\t * Returns the number of process-wide listeners registered for the given event.\n\t */\n\tstatic listenerCount(event: string): number {\n\t\treturn globalListenerCount(event);\n\t}\n\n\t/**\n\t * Emits a process-wide event. Mostly intended for tests and as a peer to\n\t * {@link RocksDatabase.on} — native code should call `emitGlobalEvent` in\n\t * `napi/global_events.h` directly rather than round-tripping through JS.\n\t *\n\t * @returns `true` if there was at least one listener.\n\t */\n\tstatic notify(event: string, ...args: any[]): boolean {\n\t\treturn globalNotify(event, args);\n\t}\n\n\t// committed\n\n\tdestroy(): void {\n\t\tthis.store.db.destroy();\n\t}\n\n\tasync drop(): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.store.db.drop(resolve, reject);\n\t\t});\n\t}\n\n\tdropSync(): void {\n\t\treturn this.store.db.dropSync();\n\t}\n\n\tget encoder(): Encoder | null {\n\t\treturn this.store.encoder;\n\t}\n\n\t/**\n\t * Flushes the underlying database by performing a commit or clearing any buffered operations.\n\t *\n\t * @return {void} Does not return a value.\n\t */\n\tflush(): Promise<void> {\n\t\treturn new Promise((resolve, reject) => this.store.db.flush(resolve, reject));\n\t}\n\n\t/**\n\t * Synchronously flushes the underlying database by performing a commit or clearing any buffered operations.\n\t *\n\t * @return {void} Does not return a value.\n\t */\n\tflushSync(): void {\n\t\treturn this.store.db.flushSync();\n\t}\n\n\t// flushed\n\n\t/**\n\t * Gets a RocksDB database property as an integer.\n\t *\n\t * @param propertyName - The name of the property to retrieve (e.g., 'rocksdb.num-blob-files').\n\t * @returns The property value as a number.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const blobFiles = db.getDBIntProperty('rocksdb.num-blob-files');\n\t * const numKeys = db.getDBIntProperty('rocksdb.estimate-num-keys');\n\t * ```\n\t */\n\tgetDBIntProperty(propertyName: string): number | undefined {\n\t\treturn this.store.db.getDBIntProperty(propertyName);\n\t}\n\n\t/**\n\t * Gets a RocksDB database property as a string.\n\t *\n\t * @param propertyName - The name of the property to retrieve (e.g., 'rocksdb.levelstats').\n\t * @returns The property value as a string.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const levelStats = db.getDBProperty('rocksdb.levelstats');\n\t * const stats = db.getDBProperty('rocksdb.stats');\n\t * ```\n\t */\n\tgetDBProperty(propertyName: string): string | undefined {\n\t\treturn this.store.db.getDBProperty(propertyName);\n\t}\n\n\t/**\n\t * Retrieves the estimated number of keys in the database.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const estimated = db.getEstimatedKeyCount();\n\t * console.log(estimated);\n\t * ```\n\t */\n\tgetEstimatedKeyCount(): number {\n\t\treturn this.getDBIntProperty('rocksdb.estimate-num-keys') ?? 0;\n\t}\n\n\t/**\n\t * Returns the current timestamp as a monotonically increasing timestamp in\n\t * milliseconds represented as a decimal number.\n\t *\n\t * @returns The current monotonic timestamp in milliseconds.\n\t */\n\tgetMonotonicTimestamp(): number {\n\t\treturn this.store.db.getMonotonicTimestamp();\n\t}\n\n\t/**\n\t * Returns a number representing a unix timestamp of the oldest unreleased\n\t * snapshot.\n\t *\n\t * @returns The oldest snapshot timestamp.\n\t */\n\tgetOldestSnapshotTimestamp(): number {\n\t\treturn this.store.db.getOldestSnapshotTimestamp();\n\t}\n\n\t/**\n\t * Gets a RocksDB statistic.\n\t *\n\t * @param statName - The name of the statistic to retrieve.\n\t * @returns The statistic value.\n\t */\n\tgetStat(statName: string): RocksDBStat {\n\t\treturn this.store.db.getStat(statName);\n\t}\n\n\t/**\n\t * Gets the RocksDB statistics. The RocksDB ticker/histogram stats require\n\t * statistics to be enabled, but the result always includes a summarized,\n\t * aggregate set of `txnlog.*` keys (across all of this database's transaction\n\t * logs), regardless of whether statistics are enabled. For detailed per-log\n\t * statistics, including memory-map usage, use `log.getStats()` on the log\n\t * returned by {@link RocksDatabase#useLog}.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const stats = db.getStats();\n\t * stats['txnlog.totalSizeBytes']; // bytes across all transaction logs\n\t * ```\n\t */\n\tgetStats(all?: false): StatsDefault;\n\tgetStats(all: true): StatsAll;\n\tgetStats(all = false): StatsDefault | StatsAll {\n\t\treturn all ? this.store.db.getStats(true) : this.store.db.getStats(false);\n\t}\n\n\t/**\n\t * Gets or creates a buffer that can be shared across worker threads.\n\t *\n\t * @param key - The key to get or create the buffer for.\n\t * @param defaultBuffer - The default buffer to copy and use if the buffer\n\t * does not exist.\n\t * @param [options] - The options for the buffer.\n\t * @param [options.callback] - A optional callback that receives\n\t * key-specific events.\n\t * @returns An `ArrayBuffer` that is internally backed by a shared block of\n\t * memory. The buffer also has `notify()` and `cancel()` methods that can be\n\t * used to notify the specified `options.callback`.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const buffer = db.getUserSharedBuffer('foo', new ArrayBuffer(10));\n\t */\n\tgetUserSharedBuffer(\n\t\tkey: Key,\n\t\tdefaultBuffer: ArrayBuffer,\n\t\toptions?: UserSharedBufferOptions\n\t): ArrayBufferWithNotify {\n\t\treturn this.store.getUserSharedBuffer(key, defaultBuffer, options);\n\t}\n\n\t/**\n\t * Returns whether the database has a lock for the given key.\n\t *\n\t * @param key - The key to check.\n\t * @returns `true` if the database has a lock for the given key, `false`\n\t * otherwise.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.hasLock('foo'); // false\n\t * db.tryLock('foo', () => {});\n\t * db.hasLock('foo'); // true\n\t * ```\n\t */\n\thasLock(key: Key): boolean {\n\t\treturn this.store.hasLock(key);\n\t}\n\n\tasync ifNoExists(_key: Key): Promise<void> {\n\t\t//\n\t}\n\n\t/**\n\t * Checks the process-global verification table for a fresh version match\n\t * on `key`. Returns `true` when the table currently records `version`. Use\n\t * this as a fast cache-freshness check before falling back to a full read:\n\t *\n\t * ```typescript\n\t * if (db.verifyVersion(key, cachedEntry.version)) {\n\t * return cachedEntry.value;\n\t * }\n\t * const value = db.getSync(key);\n\t * db.populateVersion(key, extractVersion(value));\n\t * ```\n\t */\n\tverifyVersion(key: Key, version: number): boolean {\n\t\treturn this.store.verifyVersion(key, version);\n\t}\n\n\t/**\n\t * Seeds the verification-table slot for `key` with `version`. Has no\n\t * effect if the slot is currently lock-tagged or if the verification\n\t * table is disabled.\n\t */\n\tpopulateVersion(key: Key, version: number): void {\n\t\tthis.store.populateVersion(key, version);\n\t}\n\n\t/**\n\t * Returns whether the database is open.\n\t *\n\t * @returns `true` if the database is open, `false` otherwise.\n\t */\n\tisOpen(): boolean {\n\t\treturn this.store.isOpen();\n\t}\n\n\t/**\n\t * Lists all transaction log names.\n\t *\n\t * @returns an array of transaction log names.\n\t */\n\tlistLogs(): string[] {\n\t\treturn this.store.listLogs();\n\t}\n\n\t/**\n\t * The name of the database.\n\t */\n\tget name(): string {\n\t\treturn this.#name;\n\t}\n\n\t/**\n\t * Whether the database is open in readonly mode.\n\t */\n\tget readOnly(): boolean {\n\t\treturn this.store.readOnly;\n\t}\n\n\t/**\n\t * Sugar method for opening a database.\n\t *\n\t * @param pathOrStore - The filesystem path to the database or a custom store.\n\t * @param options - The options for the database.\n\t * @returns A new RocksDatabase instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * ```\n\t */\n\tstatic open(pathOrStore: string | Store, options?: RocksDatabaseOptions): RocksDatabase {\n\t\treturn new RocksDatabase(pathOrStore, options).open();\n\t}\n\n\t/**\n\t * Opens the database. This function returns immediately if the database is\n\t * already open.\n\t *\n\t * @returns A new RocksDatabase instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = new RocksDatabase('/path/to/database');\n\t * db.open();\n\t * ```\n\t */\n\topen(): RocksDatabase {\n\t\tconst { store } = this;\n\n\t\tif (store.open()) {\n\t\t\t// already open\n\t\t\treturn this;\n\t\t}\n\n\t\tstore.db.setDefaultValueBuffer(VALUE_BUFFER);\n\t\tstore.db.setDefaultKeyBuffer(KEY_BUFFER);\n\t\tstore.db.setIteratorState(ITERATOR_STATE_BUFFER);\n\n\t\t/**\n\t\t * The encoder initialization precedence is:\n\t\t * 1. encoder.Encoder\n\t\t * 2. encoder.encode()\n\t\t * 3. encoding === `msgpack`\n\t\t * 4. encoding === `ordered-binary`\n\t\t * 5. encoder.writeKey()\n\t\t */\n\t\tlet EncoderClass: EncoderFunction | undefined = store.encoder?.Encoder;\n\t\tif (store.encoding === false) {\n\t\t\tstore.encoder = null;\n\t\t\tEncoderClass = undefined;\n\t\t} else if (typeof EncoderClass === 'function') {\n\t\t\tstore.encoder = null;\n\t\t} else if (\n\t\t\ttypeof store.encoder?.encode !== 'function' &&\n\t\t\t(!store.encoding || store.encoding === 'msgpack')\n\t\t) {\n\t\t\tstore.encoding = 'msgpack';\n\t\t\tEncoderClass = MsgpackEncoder;\n\t\t}\n\n\t\tif (EncoderClass) {\n\t\t\tconst opts: Record<string, any> = {\n\t\t\t\tcopyBuffers: true,\n\t\t\t\tfreezeData: store.freezeData,\n\t\t\t\trandomAccessStructure: store.randomAccessStructure,\n\t\t\t};\n\t\t\tconst { sharedStructuresKey } = store;\n\t\t\tif (sharedStructuresKey) {\n\t\t\t\topts.getStructures = (): any => {\n\t\t\t\t\tconst buffer = this.getBinarySync(sharedStructuresKey);\n\t\t\t\t\treturn buffer && store.decoder?.decode\n\t\t\t\t\t\t? store.decoder.decode(buffer as BufferWithDataView)\n\t\t\t\t\t\t: undefined;\n\t\t\t\t};\n\t\t\t\topts.saveStructures = (\n\t\t\t\t\tstructures: any,\n\t\t\t\t\tisCompatible: boolean | ((existingStructures: any) => boolean)\n\t\t\t\t) => {\n\t\t\t\t\treturn this.transactionSync(\n\t\t\t\t\t\t(txn: Transaction, _attempt: number) => {\n\t\t\t\t\t\t\t// note: we need to get a fresh copy of the shared structures,\n\t\t\t\t\t\t\t// so we don't want to use the transaction's getBinarySync()\n\t\t\t\t\t\t\tconst existingStructuresBuffer = this.getBinarySync(sharedStructuresKey);\n\t\t\t\t\t\t\tconst existingStructures =\n\t\t\t\t\t\t\t\texistingStructuresBuffer && store.decoder?.decode\n\t\t\t\t\t\t\t\t\t? store.decoder.decode(existingStructuresBuffer as BufferWithDataView)\n\t\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\t\tif (typeof isCompatible == 'function') {\n\t\t\t\t\t\t\t\tif (!isCompatible(existingStructures)) {\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (existingStructures && existingStructures.length !== isCompatible) {\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttxn.putSync(sharedStructuresKey, structures);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ retryOnBusy: true }\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t}\n\t\t\tstore.encoder = new EncoderClass({ ...opts, ...store.encoder });\n\t\t\tstore.decoder = store.encoder;\n\t\t} else if (typeof store.encoder?.encode === 'function') {\n\t\t\tif (!store.decoder) {\n\t\t\t\tstore.decoder = store.encoder;\n\t\t\t}\n\t\t} else if (store.encoding === 'ordered-binary') {\n\t\t\tstore.encoder = { readKey: orderedBinary.readKey, writeKey: orderedBinary.writeKey };\n\t\t\tstore.decoder = store.encoder;\n\t\t}\n\n\t\tif (typeof store.encoder?.writeKey === 'function' && !store.encoder?.encode) {\n\t\t\t// define a fallback encode method that uses writeKey to encode values\n\t\t\tstore.encoder = {\n\t\t\t\t...store.encoder,\n\t\t\t\tencode: (value: any, _mode?: number): Buffer => {\n\t\t\t\t\tconst bytesWritten = store.writeKey(value, store.encodeBuffer, 0);\n\t\t\t\t\treturn store.encodeBuffer.subarray(0, bytesWritten);\n\t\t\t\t},\n\t\t\t\tcopyBuffers: true,\n\t\t\t};\n\t\t}\n\n\t\tif (store.encoder) {\n\t\t\tstore.encoder.name = this.#name;\n\t\t}\n\n\t\tif (store.decoder && store.decoder.needsStableBuffer !== true) {\n\t\t\tstore.decoderCopies = true;\n\t\t}\n\n\t\tif (store.decoder?.readKey && !store.decoder.decode) {\n\t\t\tstore.decoder.decode = (buffer: BufferWithDataView): any => {\n\t\t\t\tif (store.decoder?.readKey) {\n\t\t\t\t\treturn store.decoder.readKey(buffer, 0, buffer.end);\n\t\t\t\t}\n\t\t\t\treturn buffer;\n\t\t\t};\n\t\t\tstore.decoderCopies = true;\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the path to the database.\n\t */\n\tget path(): string {\n\t\treturn this.store.path;\n\t}\n\n\t/**\n\t * Purges transaction logs.\n\t *\n\t * By default returns the paths of the deleted log files. Pass\n\t * `includeEntryCounts: true` to instead return, for each deleted file, its\n\t * path and the number of entries it held (`{ path, entries }`).\n\t */\n\tpurgeLogs(options: PurgeLogsOptions & { includeEntryCounts: true }): PurgedLog[];\n\tpurgeLogs(options?: PurgeLogsOptions & { includeEntryCounts?: false }): string[];\n\tpurgeLogs(options?: PurgeLogsOptions): string[] | PurgedLog[];\n\tpurgeLogs(options?: PurgeLogsOptions): string[] | PurgedLog[] {\n\t\treturn this.store.db.purgeLogs(options);\n\t}\n\n\t/**\n\t * The status of the database.\n\t */\n\tget status(): 'open' | 'closed' {\n\t\treturn this.store.isOpen() ? 'open' : 'closed';\n\t}\n\n\t/**\n\t * Executes all operations in the callback as a single transaction.\n\t *\n\t * @param callback - A async function that receives the transaction as an argument.\n\t * @returns A promise that resolves the `callback` return value.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.transaction(async (txn) => {\n\t * await txn.put('key', 'value');\n\t * });\n\t * ```\n\t */\n\tasync transaction<T>(\n\t\tcallback: TransactionCallback<T>,\n\t\toptions?: TransactionOptions\n\t): Promise<T | void> {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\tconst maxRetries = options?.maxRetries ?? 3;\n\t\tconst txn = new Transaction(this.store, options);\n\t\tlet result: T | PromiseLike<T>;\n\n\t\tthis.notify('begin-transaction');\n\n\t\tfor (let attempt = 1; attempt <= maxRetries; attempt++) {\n\t\t\ttry {\n\t\t\t\tresult = await callback(txn, attempt);\n\t\t\t} catch (callbackErr) {\n\t\t\t\treturn this.#abortTransaction(txn, callbackErr);\n\t\t\t}\n\n\t\t\tlet commitResult: typeof RETRY_NOW | void;\n\t\t\ttry {\n\t\t\t\tcommitResult = await txn.commit();\n\t\t\t} catch (commitErr) {\n\t\t\t\tif (commitErr instanceof TransactionAlreadyAbortedError) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tcommitErr instanceof TransactionRetryableError &&\n\t\t\t\t\t(options?.retryOnBusy ?? commitErr.hasLog) &&\n\t\t\t\t\tattempt < maxRetries\n\t\t\t\t) {\n\t\t\t\t\t// retry the transaction (native reset gave it a fresh snapshot; re-run the body)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthis.#abandonTransaction(txn, commitErr);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (commitResult !== RETRY_NOW) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\t// coordinatedRetry: the conflict resolved, retry immediately — but only\n\t\t\t// if attempts remain. On the final attempt a RETRY_NOW must not fall\n\t\t\t// out of the loop silently (that would resolve undefined and leave the\n\t\t\t// transaction un-aborted); abandon it like an exhausted ERR_BUSY retry.\n\t\t\tif (attempt >= maxRetries) {\n\t\t\t\tthis.#abandonTransaction(\n\t\t\t\t\ttxn,\n\t\t\t\t\tnew Error(`Transaction did not commit after ${maxRetries} coordinated retries`)\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Executes all operations in the callback as a single transaction.\n\t *\n\t * @param callback - A function that receives the transaction as an\n\t * argument. If the callback return promise-like value, it is awaited\n\t * before committing the transaction. Otherwise, the callback is treated as\n\t * synchronous.\n\t * @returns The `callback` return value.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.transaction(async (txn) => {\n\t * await txn.put('key', 'value');\n\t * });\n\t * ```\n\t */\n\ttransactionSync<T>(\n\t\tcallback: TransactionCallback<T>,\n\t\toptions?: TransactionOptions\n\t): T | PromiseLike<T> | void {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\tconst maxRetries = options?.maxRetries ?? 3;\n\n\t\tconst isRetryable = (err: Error | unknown, attempt: number) => {\n\t\t\treturn (\n\t\t\t\terr instanceof TransactionRetryableError &&\n\t\t\t\t(options?.retryOnBusy ?? err.hasLog) &&\n\t\t\t\tattempt <= maxRetries\n\t\t\t);\n\t\t};\n\n\t\tconst runAttempt = (attempt: number): T | PromiseLike<T> | void => {\n\t\t\tconst txn = new Transaction(this.store, options);\n\t\t\tlet result: T | PromiseLike<T>;\n\n\t\t\ttry {\n\t\t\t\tresult = callback(txn, attempt);\n\t\t\t} catch (callbackErr) {\n\t\t\t\treturn this.#abortTransaction(txn, callbackErr);\n\t\t\t}\n\n\t\t\t// despite being 'sync', we need to support async operations\n\t\t\tif (typeof (result as PromiseLike<T>)?.then === 'function') {\n\t\t\t\treturn (result as PromiseLike<T>).then((value: T | undefined) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttxn.commitSync();\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t} catch (commitErr) {\n\t\t\t\t\t\tif (commitErr instanceof TransactionAlreadyAbortedError) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (isRetryable(commitErr, attempt)) {\n\t\t\t\t\t\t\treturn runAttempt(attempt + 1) as PromiseLike<T>;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.#abandonTransaction(txn, commitErr);\n\t\t\t\t\t}\n\t\t\t\t}) as PromiseLike<T>;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\ttxn.commitSync();\n\t\t\t\treturn result;\n\t\t\t} catch (commitErr) {\n\t\t\t\tif (commitErr instanceof TransactionAlreadyAbortedError) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (isRetryable(commitErr, attempt)) {\n\t\t\t\t\treturn runAttempt(attempt + 1);\n\t\t\t\t}\n\t\t\t\tthis.#abandonTransaction(txn, commitErr);\n\t\t\t}\n\t\t};\n\n\t\tthis.notify('begin-transaction');\n\t\treturn runAttempt(1);\n\t}\n\n\t#abortTransaction(txn: Transaction, callbackErr: Error | unknown): void {\n\t\t// either a user error or a already aborted/committed error\n\t\ttry {\n\t\t\t// in the event of a user error, we need to abort the transaction\n\t\t\ttxn.abort();\n\t\t} catch (abortErr) {\n\t\t\tif (abortErr instanceof TransactionAlreadyAbortedError) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// rethrow the user error\n\t\tthrow callbackErr;\n\t}\n\n\t#abandonTransaction(txn: Transaction, commitErr: Error | unknown): void {\n\t\ttry {\n\t\t\ttxn.abort();\n\t\t} catch (abortErr) {\n\t\t\tif (abortErr instanceof TransactionAbandonedError) {\n\t\t\t\tthrow abortErr;\n\t\t\t}\n\t\t}\n\n\t\t// rethrow the original error\n\t\tthrow commitErr;\n\t}\n\n\t/**\n\t * Attempts to acquire a lock for a given key. If the lock is available,\n\t * the function returns `true` and the optional callback is never called.\n\t * If the lock is not available, the function returns `false` and the\n\t * callback is queued until the lock is released.\n\t *\n\t * @param key - The key to lock.\n\t * @param onUnlocked - A callback to call when the lock is released.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.tryLock('foo', () => {\n\t * console.log('lock acquired');\n\t * });\n\t * ```\n\t * @returns `true` if the lock was acquired, `false` otherwise.\n\t */\n\ttryLock(key: Key, onUnlocked?: () => void): boolean {\n\t\treturn this.store.tryLock(key, onUnlocked);\n\t}\n\n\t/**\n\t * Releases the lock on the given key and calls any queued `onUnlocked`\n\t * callback handlers.\n\t *\n\t * @param key - The key to unlock.\n\t * @returns `true` if the lock was released or `false` if the lock did not\n\t * exist.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.tryLock('foo', () => {});\n\t * db.unlock('foo'); // returns `true`\n\t * db.unlock('foo'); // already unlocked, returns `false`\n\t * ```\n\t */\n\tunlock(key: Key): void {\n\t\treturn this.store.unlock(key);\n\t}\n\n\t/**\n\t * Excecutes a function using a thread-safe lock to ensure mutual\n\t * exclusion.\n\t *\n\t * @param callback - A callback to call when the lock is acquired.\n\t * @returns A promise that resolves when the lock is acquired.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.withLock(async (waited) => {\n\t * console.log('lock acquired', waited);\n\t * });\n\t * ```\n\t */\n\twithLock(key: Key, callback: () => void | Promise<void>): Promise<void> | undefined {\n\t\treturn this.store.withLock(key, callback);\n\t}\n}\n","import { constants } from './load-binding.js';\nimport { closeSync, openSync, readSync, type Stats, statSync } from 'node:fs';\n\nconst { TRANSACTION_LOG_TOKEN, TRANSACTION_LOG_ENTRY_HEADER_SIZE } = constants;\n\n// Transaction log files did not exist before this date, so any timestamp that\n// predates it indicates corruption.\nconst MIN_VALID_TIMESTAMP = Date.UTC(2026, 0, 27); // 2026-01-27\n\n// Currently only bit 0 (TRANSACTION_LOG_ENTRY_LAST_FLAG) is defined.\nconst VALID_FLAGS_MASK = 0x01;\n\ninterface LogEntry {\n\tanomalies?: string[];\n\tdata?: Buffer;\n\tflags: number;\n\tlength: number;\n\ttimestamp?: number;\n}\n\ninterface TransactionLog {\n\tanomalies: string[];\n\tentries: LogEntry[];\n\tentryAnomalyCount: number;\n\ttimestamp: number;\n\tsize: number;\n\tversion: number;\n}\n\n/**\n * Loads an entire transaction log file into memory.\n * @param path - The path to the transaction log file.\n * @returns The transaction log.\n */\nexport function parseTransactionLog(\n\tpath: string,\n\toptions: { skipData?: boolean } = {}\n): TransactionLog {\n\tlet stats: Stats;\n\ttry {\n\t\tstats = statSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\tthrow new Error('Transaction log file does not exist');\n\t\t}\n\t\tthrow error;\n\t}\n\n\tlet { size } = stats;\n\tif (size === 0) {\n\t\tthrow new Error('Transaction log file is too small');\n\t}\n\n\tconst fileHandle = openSync(path, 'r');\n\tlet fileOffset = 0;\n\n\tconst read = (numBytes: number) => {\n\t\tconst buffer = Buffer.allocUnsafe(numBytes);\n\t\tconst bytesRead = readSync(fileHandle, buffer, 0, numBytes, fileOffset);\n\t\tfileOffset += bytesRead;\n\t\tif (bytesRead !== numBytes) {\n\t\t\t// Only hex-dump the bytes actually read, capped at 64. A corrupt length\n\t\t\t// can request a huge read; dumping the whole (largely uninitialized)\n\t\t\t// buffer can exceed V8's max string length and mask the real error.\n\t\t\tconst previewBytes = Math.min(bytesRead, 64);\n\t\t\tconst preview = buffer.subarray(0, previewBytes).toString('hex');\n\t\t\tthrow new Error(\n\t\t\t\t`Expected to read ${numBytes} bytes but only read ${bytesRead}, file offset: ${fileOffset.toString(16)}, file size: ${size}, file path: ${path}, buffer (first ${previewBytes} bytes): ${preview}`\n\t\t\t);\n\t\t}\n\t\treturn buffer;\n\t};\n\n\ttry {\n\t\t// read the file header\n\t\tconst token = read(4).readUInt32BE(0);\n\t\tif (token !== TRANSACTION_LOG_TOKEN) {\n\t\t\tthrow new Error('Invalid token');\n\t\t}\n\n\t\tconst version = read(1).readUInt8(0);\n\t\tif (version !== 1) {\n\t\t\tthrow new Error(`Unsupported transaction log file version: ${version}`);\n\t\t}\n\n\t\tconst timestamp = read(8).readDoubleBE(0);\n\t\tconst anomalies: string[] = [];\n\t\tif (!Number.isFinite(timestamp) || timestamp < MIN_VALID_TIMESTAMP) {\n\t\t\tanomalies.push(`Header timestamp ${timestamp} predates 2026-01-27 (possible corruption)`);\n\t\t}\n\n\t\t// read the entries\n\t\tconst entries: LogEntry[] = [];\n\t\tlet entryAnomalyCount = 0;\n\n\t\twhile (fileOffset < size) {\n\t\t\tconst timestamp = read(8).readDoubleBE(0);\n\t\t\tif (timestamp === 0) {\n\t\t\t\t// if we encounter zero padding, we can stop reading the entries since the next entry will start at the next 8-byte boundary, which is the same as the current file offset.\n\t\t\t\tsize = fileOffset - 8;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst length = read(4).readUInt32BE(0);\n\t\t\tconst flags = read(1).readUInt8(0);\n\t\t\t// Validate the declared length against the bytes actually remaining\n\t\t\t// before allocating. A torn/corrupt entry can claim a length far larger\n\t\t\t// than the file (e.g. a partial write that left header bytes pointing\n\t\t\t// past the data), which would otherwise drive an unbounded allocUnsafe\n\t\t\t// and OOM the process during log replay.\n\t\t\tconst remaining = size - fileOffset;\n\t\t\tif (length > remaining) {\n\t\t\t\tconst entryOffset = fileOffset - TRANSACTION_LOG_ENTRY_HEADER_SIZE;\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Corrupt entry at offset ${entryOffset.toString(16)}: declared length ${length} exceeds ${remaining} bytes remaining (file size: ${size})`\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst data = read(length);\n\n\t\t\tconst entryAnomalies: string[] = [];\n\t\t\tif (!Number.isFinite(timestamp) || timestamp < MIN_VALID_TIMESTAMP) {\n\t\t\t\tentryAnomalies.push(`timestamp ${timestamp} predates 2026-01-27 (possible corruption)`);\n\t\t\t}\n\t\t\tif ((flags & ~VALID_FLAGS_MASK) !== 0) {\n\t\t\t\tentryAnomalies.push(\n\t\t\t\t\t`flags 0x${flags.toString(16).padStart(2, '0')} contains undefined bits (expected 0x00 or 0x01)`\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst entry: LogEntry = {\n\t\t\t\ttimestamp,\n\t\t\t\tlength,\n\t\t\t\tflags,\n\t\t\t\tdata: options.skipData ? undefined : Buffer.from(data),\n\t\t\t};\n\t\t\tif (entryAnomalies.length > 0) {\n\t\t\t\tentry.anomalies = entryAnomalies;\n\t\t\t\tentryAnomalyCount += entryAnomalies.length;\n\t\t\t}\n\t\t\tentries.push(entry);\n\t\t}\n\n\t\treturn { anomalies, entries, entryAnomalyCount, timestamp, size, version };\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\terror.message = `Invalid transaction log file: ${error.message}`;\n\t\t}\n\t\tthrow error;\n\t} finally {\n\t\tcloseSync(fileHandle);\n\t}\n}\n","import {\n\tconstants,\n\ttype LogBuffer,\n\tTransactionEntry,\n\tTransactionLog,\n\tTransactionLogQueryOptions,\n} from './load-binding.js';\n\nconst FLOAT_TO_UINT32 = new Float64Array(1);\nconst UINT32_FROM_FLOAT = new Uint32Array(FLOAT_TO_UINT32.buffer);\n\nconst { TRANSACTION_LOG_FILE_HEADER_SIZE, TRANSACTION_LOG_ENTRY_HEADER_SIZE } = constants;\n\n/**\n * Returns an iterable for transaction entries within the specified range of timestamps\n * This iterable can be iterated over multiple times, and subsequent iterations will continue\n * from where the last iteration left off, allowing for iteration through the log file\n * to resume after more transactions have been committed.\n * @param start\n * @param end\n * @param exactStart - if this is true, the function will try to find the transaction that\n * exactly matches the start timestamp, and then return all subsequent transactions in the log\n * regardless of whether their timestamp is before or after the start\n */\nObject.defineProperty(TransactionLog.prototype, 'query', {\n\tvalue(\n\t\tthis: TransactionLog,\n\t\t{\n\t\t\tstart,\n\t\t\tend,\n\t\t\texactStart,\n\t\t\tstartFromLastFlushed,\n\t\t\treadUncommitted,\n\t\t\texclusiveStart,\n\t\t}: TransactionLogQueryOptions = {}\n\t): IterableIterator<TransactionEntry> {\n\t\tif (!this._lastCommittedPosition) {\n\t\t\t// if this is the first time we are querying the log, initialize the last committed position and memory map cache\n\t\t\tconst lastCommittedPosition = this._getLastCommittedPosition();\n\t\t\tthis._lastCommittedPosition = new Float64Array(lastCommittedPosition.buffer);\n\t\t\tthis._logBuffers = new Map<number, WeakRef<LogBuffer>>();\n\t\t}\n\t\tend ??= Number.MAX_VALUE;\n\n\t\tconst transactionLog = this;\n\t\tlet { logId: latestLogId, size } = loadLastPosition(this, !!readUncommitted);\n\t\tlet logId = latestLogId;\n\t\tlet position = 0;\n\t\tlet dataView: DataView;\n\t\tlet logBuffer: LogBuffer | undefined = this._currentLogBuffer; // try the current one first\n\t\tlet foundExactStart = false;\n\n\t\tif (start === undefined && !startFromLastFlushed) {\n\t\t\t// if no start timestamp is specified, start from the last committed position\n\t\t\tposition = size;\n\t\t\tif (position === 0) {\n\t\t\t\t// if the file is empty, start after the header\n\t\t\t\tposition = TRANSACTION_LOG_FILE_HEADER_SIZE;\n\t\t\t}\n\t\t\tstart = 0;\n\t\t} else {\n\t\t\tif (startFromLastFlushed) {\n\t\t\t\t// read from the last flushed position\n\t\t\t\tFLOAT_TO_UINT32[0] = this._getLastFlushed();\n\t\t\t\tif (FLOAT_TO_UINT32[0] === 0) {\n\t\t\t\t\t// no flushes have ever occurred, go to the beginning (which is actually after the file header)\n\t\t\t\t\tFLOAT_TO_UINT32[0] = this._findPosition(0);\n\t\t\t\t}\n\t\t\t\tstart ??= 0; // if no start timestamp is specified, include all\n\t\t\t} else {\n\t\t\t\t// otherwise, find the log file that contains the start timestamp, and find the position within that file\n\t\t\t\tFLOAT_TO_UINT32[0] = this._findPosition(start!);\n\t\t\t}\n\t\t\t// extract the log file ID from the 64-bit float returned by _findPosition, which is stored in the high 32 bits of the float\n\t\t\tlogId = UINT32_FROM_FLOAT[1];\n\t\t\t// and position from the low 32 bits of the float\n\t\t\tposition = UINT32_FROM_FLOAT[0];\n\t\t\tif (position === 0) {\n\t\t\t\t// if the file is empty, start after the header\n\t\t\t\tposition = TRANSACTION_LOG_FILE_HEADER_SIZE;\n\t\t\t}\n\t\t}\n\n\t\tif (logBuffer === undefined || logBuffer.logId !== logId) {\n\t\t\t// if the current log buffer is not the one we want, load the memory map\n\t\t\tlogBuffer = getLogMemoryMap(this, logId);\n\n\t\t\t// if this is the latest, cache for easy access, unless...\n\t\t\t// if we are reading uncommitted, we might be a log file ahead of the committed transaction\n\t\t\t// also, it is pointless to cache the latest log file in a memory map on Windows, because it is not growable\n\t\t\tif (logBuffer && latestLogId === logId && !readUncommitted) {\n\t\t\t\tthis._currentLogBuffer = logBuffer;\n\t\t\t}\n\n\t\t\tif (logBuffer === undefined) {\n\t\t\t\t// create a fake log buffer if we don't have any log buffer yet\n\t\t\t\tlogBuffer = Buffer.alloc(0) as unknown as LogBuffer;\n\t\t\t\tlogBuffer.logId = 0;\n\t\t\t\tlogBuffer.size = 0;\n\t\t\t\tlogBuffer.dataView = new DataView(logBuffer.buffer);\n\t\t\t\t// the outer size variable was set from loadLastPosition() above, but if we\n\t\t\t\t// couldn't acquire a memory map for that logId (e.g. the committed-position\n\t\t\t\t// references a logId that doesn't exist on disk — purged, never created, or\n\t\t\t\t// torn write of the position word), reading at any non-zero size would read\n\t\t\t\t// past the empty buffer. force size to match the empty buffer; the iterator's\n\t\t\t\t// position-vs-size logic then routes through the existing advance-to-next-log\n\t\t\t\t// path, which correctly returns done when no log file can be mapped.\n\t\t\t\tsize = 0;\n\t\t\t}\n\t\t}\n\n\t\tdataView = logBuffer.dataView;\n\n\t\tif (latestLogId !== logId) {\n\t\t\tsize = logBuffer.size;\n\t\t\tif (size === undefined) {\n\t\t\t\tsize = logBuffer.size = this.getLogFileSize(logId);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t[Symbol.iterator](): IterableIterator<TransactionEntry> {\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tnext() {\n\t\t\t\tlet timestamp: number;\n\t\t\t\tif (position >= size) {\n\t\t\t\t\t// our position is beyond the size limit, get the updated\n\t\t\t\t\t// size in case we can keep reading further from the same block\n\t\t\t\t\tconst { logId: latestLogId, size: latestSize } = loadLastPosition(\n\t\t\t\t\t\ttransactionLog,\n\t\t\t\t\t\t!!readUncommitted\n\t\t\t\t\t);\n\t\t\t\t\tsize = latestSize;\n\t\t\t\t\tif (latestLogId > logBuffer!.logId) {\n\t\t\t\t\t\t// if it is not the latest log, get the file size\n\t\t\t\t\t\tsize =\n\t\t\t\t\t\t\tlogBuffer!.size ??\n\t\t\t\t\t\t\t(logBuffer!.size = transactionLog.getLogFileSize(logBuffer!.logId));\n\t\t\t\t\t\tif (position >= size) {\n\t\t\t\t\t\t\t// we can't read any further in this block, go to the next block\n\t\t\t\t\t\t\tconst nextLogBuffer = getLogMemoryMap(transactionLog, logBuffer!.logId + 1)!;\n\t\t\t\t\t\t\tif (nextLogBuffer) {\n\t\t\t\t\t\t\t\tdataView = nextLogBuffer.dataView;\n\t\t\t\t\t\t\t\tlogBuffer = nextLogBuffer;\n\t\t\t\t\t\t\t\tif (latestLogId > logBuffer!.logId) {\n\t\t\t\t\t\t\t\t\t// it is non-current log file, we can safely use or cache the size\n\t\t\t\t\t\t\t\t\tsize =\n\t\t\t\t\t\t\t\t\t\tlogBuffer!.size ??\n\t\t\t\t\t\t\t\t\t\t(logBuffer!.size = transactionLog.getLogFileSize(logBuffer!.logId));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tsize = latestSize; // use the latest position from loadLastPosition\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tposition = TRANSACTION_LOG_FILE_HEADER_SIZE;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile (position < size) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttimestamp = dataView.getFloat64(position);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t(error as Error).message += ` at position ${position.toString(16)} of log ${\n\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t} (size=${size}, log buffer length=${logBuffer!.length})`;\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\tif (!timestamp) {\n\t\t\t\t\t\t// we have gone beyond the last transaction and reached the end\n\t\t\t\t\t\treturn { done: true, value: undefined };\n\t\t\t\t\t}\n\n\t\t\t\t\t// Corruption bound: a committed read can't legitimately extend past\n\t\t\t\t\t// the committed `size` (a true entry boundary); an uncommitted read is\n\t\t\t\t\t// bounded only by the physically mapped buffer. In both cases the bound\n\t\t\t\t\t// is also clamped to `logBuffer.length` — if committed `size` over-reports\n\t\t\t\t\t// the mapped buffer (e.g. a truncated/torn file), an unclamped `size`\n\t\t\t\t\t// would let `position` advance past the buffer and `subarray` silently\n\t\t\t\t\t// return a truncated frame instead of throwing. A torn/corrupt entry\n\t\t\t\t\t// can declare a length far past this bound — without the checks below,\n\t\t\t\t\t// `position` runs past the buffer, `subarray` hands back a misframed\n\t\t\t\t\t// (garbage) transaction, and the advance-to-next-log path can\n\t\t\t\t\t// dereference an undefined buffer. Fail loudly with a bounded error.\n\t\t\t\t\tconst limit = readUncommitted ? logBuffer!.length : Math.min(size, logBuffer!.length);\n\t\t\t\t\tif (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE > limit) {\n\t\t\t\t\t\tthrow new RangeError(\n\t\t\t\t\t\t\t`Corrupt transaction log: truncated entry header at position ${position.toString(16)} of log ${\n\t\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t\t} (available=${limit - position})`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst length = dataView.getUint32(position + 8);\n\t\t\t\t\tif (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE + length > limit) {\n\t\t\t\t\t\tthrow new RangeError(\n\t\t\t\t\t\t\t`Corrupt transaction log entry at position ${position.toString(16)} of log ${\n\t\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t\t}: declared length ${length} overruns the log (limit=${limit})`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tposition += TRANSACTION_LOG_ENTRY_HEADER_SIZE;\n\t\t\t\t\tlet matchesRange: boolean;\n\t\t\t\t\tif (foundExactStart) {\n\t\t\t\t\t\t// already found the exact start, only need to match on remaining conditions\n\t\t\t\t\t\tmatchesRange = (!exclusiveStart || timestamp !== start) && timestamp < end;\n\t\t\t\t\t} else if (exactStart) {\n\t\t\t\t\t\t// in exact start mode, we are look for the exact identifying timestamp of the first transaction\n\t\t\t\t\t\tif (timestamp === start) {\n\t\t\t\t\t\t\tmatchesRange = !exclusiveStart;\n\t\t\t\t\t\t\t// after finding this transaction, match all remaining (but still respecting end and exclusiveStart\n\t\t\t\t\t\t\tfoundExactStart = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmatchesRange = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// no exact start, so just match on conditions\n\t\t\t\t\t\tmatchesRange =\n\t\t\t\t\t\t\t(exclusiveStart ? timestamp > start! : timestamp >= start!) && timestamp < end;\n\t\t\t\t\t}\n\t\t\t\t\tconst entryStart = position;\n\t\t\t\t\tposition += length;\n\t\t\t\t\tif (matchesRange) {\n\t\t\t\t\t\t// fits in the same block, just subarray the data out\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tdone: false,\n\t\t\t\t\t\t\tvalue: {\n\t\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\tendTxn: Boolean(logBuffer![entryStart - 1] & 1),\n\t\t\t\t\t\t\t\tdata: logBuffer!.subarray(entryStart, position),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tif (position >= size) {\n\t\t\t\t\t\t// move to the next log file\n\t\t\t\t\t\tconst { logId: latestLogId, size: latestSize } = loadLastPosition(\n\t\t\t\t\t\t\ttransactionLog,\n\t\t\t\t\t\t\t!!readUncommitted\n\t\t\t\t\t\t);\n\t\t\t\t\t\tsize = latestSize;\n\t\t\t\t\t\tif (latestLogId > logBuffer!.logId) {\n\t\t\t\t\t\t\tconst nextLogBuffer = getLogMemoryMap(transactionLog, logBuffer!.logId + 1);\n\t\t\t\t\t\t\tif (!nextLogBuffer) {\n\t\t\t\t\t\t\t\t// the next log file can't be mapped (purged, mid-rotation,\n\t\t\t\t\t\t\t\t// 0-byte at mmap time, FS race); stop cleanly rather than\n\t\t\t\t\t\t\t\t// dereferencing an undefined buffer\n\t\t\t\t\t\t\t\treturn { done: true, value: undefined };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlogBuffer = nextLogBuffer;\n\t\t\t\t\t\t\tdataView = logBuffer.dataView;\n\t\t\t\t\t\t\tsize = logBuffer.size;\n\t\t\t\t\t\t\tif (size == undefined) {\n\t\t\t\t\t\t\t\tsize = transactionLog.getLogFileSize(logBuffer.logId);\n\t\t\t\t\t\t\t\tif (!readUncommitted) {\n\t\t\t\t\t\t\t\t\tlogBuffer.size = size;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tposition = TRANSACTION_LOG_FILE_HEADER_SIZE;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { done: true, value: undefined };\n\t\t\t},\n\t\t};\n\t},\n});\n\nfunction getLogMemoryMap(transactionLog: TransactionLog, logId: number): LogBuffer | undefined {\n\tif (logId <= 0) {\n\t\treturn;\n\t}\n\tlet logBuffer = transactionLog._logBuffers!.get(logId)?.deref();\n\tif (logBuffer) {\n\t\t// if we have a cached buffer, return it\n\t\treturn logBuffer;\n\t}\n\ttry {\n\t\tlogBuffer = transactionLog._getMemoryMapOfFile(logId);\n\t} catch (error) {\n\t\t(error as Error).message += ` (log file ID: ${logId})`;\n\t\tthrow error;\n\t}\n\tif (!logBuffer) {\n\t\treturn;\n\t}\n\tlogBuffer.logId = logId;\n\tlogBuffer.dataView = new DataView(logBuffer.buffer);\n\ttransactionLog._logBuffers!.set(logId, new WeakRef(logBuffer)); // add to cache\n\tlet maxMisses = 3;\n\tfor (const [logId, reference] of transactionLog._logBuffers!) {\n\t\t// clear out any references that have been collected\n\t\tif (reference.deref() === undefined) {\n\t\t\ttransactionLog._logBuffers!.delete(logId);\n\t\t} else if (--maxMisses === 0) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn logBuffer;\n}\n\nfunction loadLastPosition(\n\ttransactionLog: TransactionLog,\n\treadUncommitted: boolean\n): { logId: number; size: number } {\n\t// atomically copy the full 64-bit last committed position word to a local variable so we can read it without memory tearing\n\tFLOAT_TO_UINT32[0] = transactionLog._lastCommittedPosition![0];\n\tlet logId = UINT32_FROM_FLOAT[1];\n\tlet size = 0;\n\n\tif (readUncommitted) {\n\t\t// if we are reading uncommitted transactions, we need to read the entire log file to find the latest position\n\t\tlet nextSize = 0;\n\t\tlet nextLogId = logId || 1;\n\t\twhile (true) {\n\t\t\tnextSize = transactionLog.getLogFileSize(nextLogId);\n\t\t\tif (nextSize === 0) {\n\t\t\t\t// if the size is zero, there is no next log file, we are done\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tsize = nextSize;\n\t\t\t\tlogId = nextLogId++;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// otherwise, just use the last committed position, which indicates the latest committed transaction in the log\n\t\tsize = UINT32_FROM_FLOAT[0];\n\t}\n\treturn { logId, size };\n}\n","import { version } from './load-binding.js';\n\nexport {\n\tbackups,\n\ttype BackupInfo,\n\ttype BackupOptions,\n\ttype RestoreMode,\n\ttype RestoreOptions,\n} from './backup.js';\nexport type { BackupStreamOptions } from './backup-stream.js';\nexport {\n\tRocksDatabase,\n\ttype RocksDatabaseOptions,\n\ttype RocksDBStat,\n\ttype RocksDBStats,\n} from './database.js';\nexport { DBIterator } from './dbi-iterator.js';\nexport { DBI, type IteratorOptions } from './dbi.js';\nexport type { Key } from './encoding.js';\nexport type * from './stats.js';\nexport {\n\tconstants,\n\tcoolTransactionLogs,\n\tcurrentThreadId,\n\tfileLockRelease,\n\ttryFileLock,\n\tregistryStatus,\n\tstats,\n\tshutdown,\n\tsupportedCompression,\n\tTransactionLog,\n\ttype TransactionEntry,\n\ttype TransactionLogPosition,\n\ttype TransactionLogStats,\n} from './load-binding.js';\nexport * from './parse-transaction-log.js';\nexport {\n\tvalidateTransactionLogStore,\n\ttype TransactionLogFileValidation,\n\ttype TransactionLogStoreValidation,\n\ttype ValidateTransactionLogStoreOptions,\n} from './validate-transaction-log.js';\nexport {\n\ttype CompressionAlgorithm,\n\ttype CompressionInfo,\n\ttype CompressionOption,\n\tStore,\n\ttype StoreContext,\n\ttype StoreGetOptions,\n\ttype StoreIteratorOptions,\n\ttype StorePutOptions,\n\ttype StoreRangeOptions,\n\ttype StoreRemoveOptions,\n} from './store.js';\nexport { Transaction } from './transaction.js';\n\nimport './transaction-log-reader.js';\n\nexport const versions: { rocksdb: string; 'rocksdb-js': string } = {\n\trocksdb: version,\n\t'rocksdb-js': 'ROCKSDB_JS_VERSION',\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["FRESH_VERSION_FLAG","resolvePath","#store","#reverse","#start","#end","#exclusiveStart","#inclusiveEnd","#traversed","#cursor","#memoized","#finished","FRESH_VERSION_FLAG","#sink","#finalized","#remaining","#pad","#includeValues","#limit","#yielded","#claimed","#txn","#handleCommitError","#name","MsgpackEncoder","#abortTransaction","#abandonTransaction","TRANSACTION_LOG_ENTRY_HEADER_SIZE"],"sources":["../src/load-binding.ts","../src/validate-transaction-log.ts","../src/backup.ts","../src/count-estimator.ts","../src/util.ts","../src/dbi.ts","../src/tar.ts","../src/backup-stream.ts","../src/dbi-iterator.ts","../src/encoding.ts","../src/store.ts","../src/transaction.ts","../src/database.ts","../src/parse-transaction-log.ts","../src/transaction-log-reader.ts","../src/index.ts"],"sourcesContent":["import type { BackupInfo, BackupOptions, RestoreOptions } from './backup.ts';\nimport type { RangeOptions } from './dbi.ts';\nimport type { BufferWithDataView, Key } from './encoding.ts';\nimport type { StatsAll, StatsDefault, StatsHistogramData } from './stats.ts';\nimport type { StoreContext } from './store.ts';\nimport type { TransactionLogStoreValidation } from './validate-transaction-log.ts';\nexport type {\n\tGetStatsMethod,\n\tStatsAll,\n\tStatsAllExtras,\n\tStatsBasics,\n\tStatsCurated,\n\tStatsCuratedExtras,\n\tStatsDefault,\n\tStatsHistogramData,\n\tStatsValue,\n} from './stats.ts';\nimport { execSync } from 'node:child_process';\nimport { readdirSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/**\n * The `Error` subclass passed to `'error'` event listeners and returned by\n * `db.getLastError()` when RocksDB reports a background error (e.g. a write\n * failing at the filesystem level). A real `Error` instance (`instanceof Error`\n * and `instanceof BackgroundError` both hold) with the fields below. Only a\n * hard-or-worse error (`writesDisabled`) stops writes; a soft error is\n * auto-recoverable. When `writesDisabled` is `true` and the underlying condition\n * has cleared, call {@link RocksDatabase.resume}. See HarperFast/rocksdb-js#730.\n *\n * The runtime constructor is defined natively and exported as\n * {@link BackgroundError}; the same name is both a value (for `instanceof`) and\n * this instance type.\n *\n * @example\n * ```typescript\n * db.on('error', (err: BackgroundError) => {\n * if (err.writesDisabled) console.error(`writes disabled: ${err.message}`);\n * });\n * ```\n */\nexport interface BackgroundError extends Error {\n\t/** Always `'BackgroundError'`. */\n\tname: string;\n\t/** Discriminator for the error class; always `'background'` here. */\n\ttype: string;\n\t/**\n\t * The RocksDB `Status::Severity` as a number: 1 soft, 2 hard, 3 fatal,\n\t * 4 unrecoverable.\n\t */\n\tseverity: number;\n\t/** Human-readable severity: `'soft'`, `'hard'`, `'fatal'`, or `'unrecoverable'`. */\n\tseverityName: string;\n\t/**\n\t * Whether RocksDB has disabled writes on the database in response to this\n\t * error (severity hard or worse, i.e. `severity >= 2`). Only when `true` is\n\t * {@link RocksDatabase.resume} warranted; a soft error auto-recovers and\n\t * leaves writes enabled. Distinct from opening the database in read-only\n\t * mode — this is RocksDB halting writes after a background failure.\n\t */\n\twritesDisabled: boolean;\n\t/**\n\t * The RocksDB `BackgroundErrorReason` as a number, present when the error\n\t * originated from a reason-bearing callback (flush, compaction, etc.).\n\t */\n\treason?: number;\n\t/** Human-readable reason, e.g. `'flush'` or `'compaction'`. */\n\treasonName?: string;\n}\n\n/**\n * The shape accepted by `db.setLastError(...)` to inject or reset a background\n * error. `message` is required; the rest default/omit as with a real error.\n * `type` defaults to `'background'`. Pass `null`/nothing to `setLastError` to\n * clear instead of an object of this shape.\n */\nexport type BackgroundErrorOptions = {\n\tmessage: string;\n\tseverity?: number;\n\tseverityName?: string;\n\twritesDisabled?: boolean;\n\treason?: number;\n\treasonName?: string;\n\ttype?: string;\n};\n\nexport type NativeTransactionOptions = {\n\t/**\n\t * Whether to disable snapshots.\n\t *\n\t * @default false\n\t */\n\tdisableSnapshot?: boolean;\n\n\t/**\n\t * When `true`, an `IsBusy` conflict at commit time is resolved with the\n\t * `RETRY_NOW` sentinel value instead of being rejected. The native layer\n\t * may park on a VT slot before resolving, so the JS retry fires only after\n\t * the conflicting transaction has committed and released its write intent.\n\t *\n\t * Use together with `verificationTable: true` on the database.\n\t *\n\t * @default false\n\t */\n\tcoordinatedRetry?: boolean;\n};\n\nexport type NativeTransaction = {\n\tid: number;\n\tnew (context: NativeDatabase, options?: NativeTransactionOptions): NativeTransaction;\n\tabandonWrites(): void;\n\tabort(): void;\n\tcommit(resolve: (retrySignal?: number) => void, reject: (err: Error) => void): void;\n\tcommitSync(): void;\n\t// Note that keyLengthOrKeyBuffer can be the length of the key if it was written into the shared buffer, or a direct buffer\n\tget(\n\t\tkeyLengthOrKeyBuffer: number | Buffer,\n\t\tresolve: (value: Buffer | number) => void,\n\t\treject: (err: Error) => void,\n\t\ttxnIdIgnored?: number,\n\t\texpectedVersion?: number\n\t): number;\n\tgetCount(options?: RangeOptions): number;\n\tgetSync(keyLengthOrKeyBuffer: number | Buffer): Buffer | number | undefined;\n\tgetTimestamp(): number;\n\tputSync(key: Key, value: Buffer | Uint8Array, txnId?: number): void;\n\tremoveSync(key: Key): void;\n\tsetTimestamp(timestamp?: number): void;\n\t// The transaction holds no napi_ref to its database (#741), so the owning\n\t// NativeDatabase must be supplied per-call; native rejects a foreign one.\n\tuseLog(name: string | number, jsDatabase: NativeDatabase): TransactionLog;\n};\n\nexport type LogBuffer = Buffer & {\n\tdataView: DataView;\n\tlogId: number;\n\tsize: number;\n};\n\nexport type TransactionLogQueryOptions = {\n\tstart?: number;\n\tend?: number;\n\texactStart?: boolean;\n\tstartFromLastFlushed?: boolean;\n\treadUncommitted?: boolean;\n\texclusiveStart?: boolean;\n};\n\nexport type TransactionEntry = {\n\ttimestamp: number;\n\tdata: Buffer;\n\tendTxn: boolean;\n};\n\n/**\n * A position within a transaction log, identifying a log file by its sequence\n * number and a byte `offset` within that file.\n */\nexport type TransactionLogPosition = { sequence: number; offset: number };\n\n/**\n * A detailed statistics snapshot for a single transaction log store, returned\n * by {@link TransactionLog.getStats}. All sizes are in bytes; timestamps are\n * milliseconds since the Unix epoch.\n *\n * Memory note: `memory.mappedBytes` is virtual address space — the active write\n * file is mapped at the full configured `maxFileSize` on POSIX, so it does not\n * reflect resident memory. `memory.overlayBytes` (POSIX only; 0 on Windows) is\n * the file-backed portion and is the closer proxy for real consumption.\n */\nexport type TransactionLogStats = {\n\tname: string;\n\tpath: string;\n\tfileCount: number;\n\tcurrentSequenceNumber: number;\n\toldestSequenceNumber: number;\n\ttotalSizeBytes: number;\n\tcurrentFileSize: number;\n\tpendingTransactions: number;\n\tuncommittedTransactions: number;\n\treplayGapBytes: number;\n\tmemory: {\n\t\tmappedBytes: number;\n\t\toverlayBytes: number;\n\t\tactiveMaps: number;\n\t};\n\tnextLogPosition: TransactionLogPosition;\n\tlastFlushedPosition: TransactionLogPosition;\n\tlastCommittedPosition: TransactionLogPosition | null;\n\tpurge: {\n\t\toldestFileAgeMs: number;\n\t\tpurgeableFiles: number;\n\t\tretainedUnflushedFiles: number;\n\t\tlastPurgeMs: number;\n\t};\n\ttotals: {\n\t\ttransactionsWritten: number;\n\t\tentriesWritten: number;\n\t\tbytesWritten: number;\n\t\trotations: number;\n\t\tfilesPurged: number;\n\t\tbytesPurged: number;\n\t\tpurgeRuns: number;\n\t\tdatabaseFlushes: number;\n\t\twriteFailures: number;\n\t};\n\tconfig: {\n\t\tmaxFileSize: number;\n\t\tretentionMs: number;\n\t\tmaxAgeThreshold: number;\n\t};\n};\n\nexport type TransactionLog = {\n\tnew (db: NativeDatabase, name: string): TransactionLog;\n\taddEntry(data: Buffer | Uint8Array, txnId?: number): void;\n\tgetLogFileSize(sequenceId?: number): number;\n\tgetStats(): TransactionLogStats;\n\tname: string;\n\tpath: string;\n\tquery(options?: TransactionLogQueryOptions): IterableIterator<TransactionEntry>;\n\t_currentLogBuffer: LogBuffer;\n\t_findPosition(timestamp: number): number;\n\t_getLastCommittedPosition(): Buffer;\n\t_getLastFlushed(): number;\n\t_getMemoryMapOfFile(sequenceId: number): LogBuffer | undefined;\n\t_lastCommittedPosition: Float64Array;\n\t_logBuffers: Map<number, WeakRef<LogBuffer>>;\n};\n\n/**\n * Shape of options that can be passed to the native iterator constructor for\n * the rare case of advanced RocksDB ReadOptions overrides. Common iterator\n * options are passed via the bitmask `flags` argument instead.\n */\nexport type NativeIteratorAdvancedOptions = {\n\tadaptiveReadahead?: boolean;\n\tasyncIO?: boolean;\n\tautoReadaheadSize?: boolean;\n\tbackgroundPurgeOnIteratorCleanup?: boolean;\n\tfillCache?: boolean;\n\treadaheadSize?: number;\n\ttailing?: boolean;\n};\n\n/**\n * The result of a single native iterator step. A number value matches one of\n * the `ITERATOR_RESULT_*` constants. The slow-path object is returned when\n * the data does not fit in the shared key/value buffers, or when the decoder\n * needs a stable value buffer.\n */\nexport type NativeIteratorResult = number | { key: Buffer; value?: Buffer };\n\nexport declare class NativeIteratorCls {\n\tconstructor(\n\t\tcontext: StoreContext,\n\t\tflags: number,\n\t\tstartKeyEnd: number,\n\t\tendKeyStart: number,\n\t\tendKeyEnd: number,\n\t\toptions?: NativeIteratorAdvancedOptions\n\t);\n\tnext(): NativeIteratorResult;\n\treturn(): void;\n\tthrow(err?: unknown): void;\n}\n\nexport type NativeDatabaseMode = 'optimistic' | 'pessimistic';\n\nexport type NativeDatabaseOptions = {\n\t/**\n\t * The friendly name of a compression algorithm compiled into this RocksDB\n\t * build (see `supportedCompression`), e.g. `'lz4'`, `'zstd'`, `'none'`. The\n\t * higher-level `StoreOptions.compression` (which also accepts an object with\n\t * a level) is normalized down to this string plus `compressionLevel`.\n\t */\n\tcompression?: string;\n\t/**\n\t * Compression level forwarded to RocksDB's `compression_opts.level`. Meaning\n\t * is algorithm-specific; omit to use the algorithm's default.\n\t */\n\tcompressionLevel?: number;\n\t/**\n\t * Apply `compression` to every column family the underlying `DB::Open` opens, rather than\n\t * only the one named by `name`. Requires an explicit `compression`.\n\t */\n\tcompressionForAllColumnFamilies?: boolean;\n\tdbWriteBufferSize?: number;\n\tdisableWAL?: boolean;\n\tenableStats?: boolean;\n\t/**\n\t * Verbosity of RocksDB's informational logging (`info_log_level`): `0`\n\t * (debug), `1` (info), `2` (warn), `3` (error), `4` (fatal), or `5`\n\t * (header-only). Omit to leave RocksDB's own default (`INFO_LEVEL` in a\n\t * release build of the linked RocksDB library).\n\t */\n\tinfoLogLevel?: number;\n\t/**\n\t * Per-file size cap (bytes) for informational log files (`LOG` /\n\t * `LOG.old.*`, `max_log_file_size`). RocksDB retains up to 5 of these files\n\t * (`keep_log_file_num`, not currently exposed as an option), so total\n\t * informational-log footprint is bounded at roughly `5 * maxLogFileSize`.\n\t *\n\t * @default 16777216 (16MB)\n\t */\n\tmaxLogFileSize?: number;\n\tmaxOpenFiles?: number;\n\tmaxWriteBufferNumber?: number;\n\tmaxWriteBufferSizeToMaintain?: number;\n\tmode?: NativeDatabaseMode;\n\tname?: string;\n\tnoBlockCache?: boolean;\n\tparallelismThreads?: number;\n\treadOnly?: boolean;\n\tstatsLevel?: (typeof stats.StatsLevel)[keyof typeof stats.StatsLevel];\n\ttransactionLogMaxAgeThreshold?: number;\n\ttransactionLogMaxSize?: number;\n\ttransactionLogRetentionMs?: number;\n\ttransactionLogsPath?: string;\n\t/**\n\t * When true, transaction writes to this column family invalidate the\n\t * VerificationTable slot for each written key at write time (not at\n\t * commit time). Enable only for column families whose records are\n\t * cached (e.g. the primary CF of a table). Default: false.\n\t */\n\tverificationTable?: boolean;\n\twriteBufferSize?: number;\n};\n\ntype ResolveCallback<T> = (value: T) => void;\ntype RejectCallback = (err: Error) => void;\n\nexport type UserSharedBufferCallback = () => void;\n\nexport type PurgeLogsOptions = {\n\tbefore?: number;\n\tdestroy?: boolean;\n\t/**\n\t * When `true`, count the entries in each purged log file (extra work) and\n\t * return `PurgedLog[]` instead of the default `string[]` of file paths.\n\t */\n\tincludeEntryCounts?: boolean;\n\tname?: string;\n};\n\n/**\n * A purged transaction log file and the number of entries it held, returned by\n * `purgeLogs()` when `includeEntryCounts` is `true`.\n */\nexport type PurgedLog = { path: string; entries: number };\n\nexport type FlushOptions = {\n\t/**\n\t * Whether the flush may proceed even though it will stall writes for its duration.\n\t *\n\t * Maps to `rocksdb::FlushOptions::allow_write_stall`. RocksDB's default is `false`, which\n\t * means the opposite of what the name suggests on first read: the flush **waits** until it\n\t * can run without causing a stall. That wait has no timeout, so a database sitting in a stall\n\t * condition — immutable-memtable backlog, L0 stop trigger, pending-compaction-bytes limit, an\n\t * exhausted WriteBufferManager budget — blocks the caller for as long as the condition lasts.\n\t * `flush()` runs on the libuv threadpool, so there the wait shows up as a promise that simply\n\t * never settles while the event loop stays alive — and it parks that whole worker, not just\n\t * the caller's promise: `UV_THREADPOOL_SIZE` defaults to 4, so a handful of concurrently\n\t * stalled flushes can exhaust the pool and stall every unrelated `fs`/`dns`/`crypto` call and\n\t * cold-cache `get()` in the process, not only this database's own operations. `flushSync()`\n\t * takes the same wait on the JS thread, so it is the worse of the two here rather than the\n\t * safer one: it freezes the event loop outright instead of parking a pool worker, and it holds\n\t * the in-flight operation claim that `close()` waits on for the duration.\n\t *\n\t * Pass `true` when the flush is a durability gate the caller is blocked on and stalling\n\t * writers is the acceptable cost of it completing — decide that up front, before issuing the\n\t * call, since there is no way to cancel an in-flight `flush()` and turn `true` into an escape\n\t * hatch after the fact. It is also not a free way out of an existing stall: forcing the\n\t * memtable switch adds another L0 file to the level whose file count may be *causing* the\n\t * stop trigger, so it can prolong the condition it is meant to clear. Weigh the cost\n\t * database-wide, not per-caller: a flush covers **every column family** on the database, and\n\t * the descriptor is process-global and shared across `worker_threads`, so the stall lands on\n\t * every other column family and every other handle that opened the same path — not just the\n\t * one you called. It also relocates the hang rather than removing it: a stalled `db->Write()`\n\t * blocks the database's single `CommitWorker` thread, which dispatches every\n\t * `Transaction.commit()` in order, so the stall queues up every commit behind it — including\n\t * ones from callers that never touched flush — until the stall clears.\n\t *\n\t * Note this is a *different* knob from the `writeBufferManagerAllowStall` config, and their\n\t * polarity is nearly opposite: that one decides whether the WriteBufferManager may stall\n\t * writers at all, this one decides whether a manual flush is willing to cause a stall rather\n\t * than wait one out.\n\t *\n\t * @default false\n\t */\n\tallowWriteStall?: boolean;\n};\n\nexport type NativeDatabase = {\n\tnew (): NativeDatabase;\n\taddListener(event: string, callback: (...args: any[]) => void): void;\n\tbackup(\n\t\tresolve: ResolveCallback<number>,\n\t\treject: RejectCallback,\n\t\tbackupDir: string,\n\t\toptions?: BackupOptions\n\t): void;\n\t// `emit` is invoked once per file header (kind 0: name, size, mtime) and once\n\t// per payload chunk (kind 1: Buffer). It must return a promise; native awaits\n\t// it before producing the next event (backpressure), and a rejection aborts.\n\tbackupStream(\n\t\tresolve: ResolveCallback<void>,\n\t\treject: RejectCallback,\n\t\temit: (kind: number, data: string | Uint8Array, size: number, mtime: number) => Promise<void>,\n\t\toptions?: { flushBeforeBackup?: boolean; transactionLogs?: boolean }\n\t): void;\n\tclear(resolve: ResolveCallback<void>, reject: RejectCallback): void;\n\tclearSync(): void;\n\tclose(): void;\n\tcompact(\n\t\tresolve: ResolveCallback<void>,\n\t\treject: RejectCallback,\n\t\tstart?: Key,\n\t\tend?: Key,\n\t\tbottommost?: boolean\n\t): void;\n\tcompactSync(start?: Key, end?: Key, bottommost?: boolean): void;\n\tcolumns: string[];\n\tcreateCheckpoint(\n\t\tresolve: ResolveCallback<void>,\n\t\treject: RejectCallback,\n\t\ttargetPath: string\n\t): void;\n\tdestroy(): void;\n\tdrop(resolve: ResolveCallback<void>, reject: RejectCallback): void;\n\tdropSync(): void;\n\tflush(resolve: ResolveCallback<void>, reject: RejectCallback, options?: FlushOptions): void;\n\tflushSync(options?: FlushOptions): void;\n\tnotify(event: string | BufferWithDataView, args?: any[]): boolean;\n\t// Note that keyLengthOrKeyBuffer can be the length of the key if it was written into the shared buffer, or a direct buffer\n\tget(\n\t\tkeyLengthOrKeyBuffer: number | Buffer,\n\t\tresolve: ResolveCallback<Buffer | number>,\n\t\treject: RejectCallback,\n\t\ttxnId?: number,\n\t\texpectedVersion?: number\n\t): number;\n\testimateCount(startKey?: Buffer, endKey?: Buffer): { count: number; confidence: number };\n\tgetCompression(): { algorithm: string; level?: number };\n\tgetCount(options?: RangeOptions, txnId?: number): number;\n\tgetLastError(): BackgroundError | null;\n\tsetLastError(error?: BackgroundErrorOptions | null): void;\n\tgetDBIntProperty(propertyName: string): number | undefined;\n\tgetDBProperty(propertyName: string): string | undefined;\n\tgetLogOptions(): { maxLogFileSize: number; infoLogLevel: number };\n\tgetMonotonicTimestamp(): number;\n\tgetOldestSnapshotTimestamp(): number;\n\tgetStat(statName: string): number | StatsHistogramData;\n\tgetStats(all?: false): StatsDefault;\n\tgetStats(all: true): StatsAll;\n\tgetSync(\n\t\tkeyLengthOrKeyBuffer: number | Buffer,\n\t\tflags: number,\n\t\ttxnId?: number,\n\t\texpectedVersion?: number\n\t): Buffer;\n\tgetUserSharedBuffer(\n\t\tkey: BufferWithDataView,\n\t\tdefaultBuffer: ArrayBuffer,\n\t\tcallback?: UserSharedBufferCallback\n\t): ArrayBuffer;\n\thasLock(key: BufferWithDataView): boolean;\n\tlisteners(event: string | BufferWithDataView): number;\n\tlistLogs(): string[];\n\topened: boolean;\n\topen(path: string, options?: NativeDatabaseOptions): void;\n\tpopulateVersion(keyLengthOrKeyBuffer: number | Buffer, version: number): void;\n\tpurgeLogs(options: PurgeLogsOptions & { includeEntryCounts: true }): PurgedLog[];\n\tpurgeLogs(options?: PurgeLogsOptions & { includeEntryCounts?: false }): string[];\n\tpurgeLogs(options?: PurgeLogsOptions): string[] | PurgedLog[];\n\tputSync(key: BufferWithDataView, value: any, txnId?: number): void;\n\tremoveListener(event: string | BufferWithDataView, callback: () => void): boolean;\n\tremoveSync(key: BufferWithDataView, txnId?: number): void;\n\tresume(): void;\n\t// Provide a buffer that is used as the default/shared buffer for keys, where functions that provide a key can do so by assigning the key to the shared buffer and providing the length.\n\t// A null value will reset the buffer.\n\tsetDefaultKeyBuffer(buffer: Buffer | Uint8Array | null): void;\n\t// Provide a buffer that is used as the default/shared buffer for value, where functions that use or return a value can do so by assigning the value to the shared buffer and providing/returning the length.\n\t// A null value will reset the buffer.\n\tsetDefaultValueBuffer(buffer: Buffer | Uint8Array | null): void;\n\t// Provide a Uint32Array(2)-backed buffer used by iterators to communicate\n\t// the key length (index 0) and value length (index 1) of each iteration\n\t// step without per-iteration NAPI property accesses.\n\tsetIteratorState(buffer: Buffer | Uint8Array): void;\n\ttryLock(key: BufferWithDataView, callback?: () => void): boolean;\n\tunlock(key: BufferWithDataView): void;\n\t// jsDatabase is accepted (and ignored) so Store.useLog can pass it\n\t// unconditionally for both StoreContext shapes; only the transaction\n\t// variant consumes it.\n\tuseLog(name: string, jsDatabase?: NativeDatabase): TransactionLog;\n\tverifyVersion(keyLengthOrKeyBuffer: number | Buffer, version: number): boolean;\n\twithLock(key: BufferWithDataView, callback: () => void | Promise<void>): Promise<void>;\n};\n\nexport type RocksDatabaseConfig = {\n\tblockCacheSize?: number;\n\t/**\n\t * Number of slots in the process-global verification table. Each slot is\n\t * 8 bytes; the default of 128K slots is 1 MB. Set to 0 to disable.\n\t *\n\t * Must be configured before the first database is opened. Once the table\n\t * is materialized, attempts to change this value will throw.\n\t */\n\tverificationTableEntries?: number;\n\tcompactOnClose?: boolean;\n\t/**\n\t * Total memtable memory limit (bytes) shared across every database opened\n\t * in this process. When set, RocksDB uses a single `WriteBufferManager` so\n\t * write buffers are bounded process-wide rather than per database. 0 (the\n\t * default) disables the manager.\n\t *\n\t * Can be updated at runtime; the new size takes effect on the existing\n\t * manager via `SetBufferSize`.\n\t */\n\twriteBufferManagerSize?: number;\n\t/**\n\t * When `true`, memtable memory is \"charged\" against the shared block cache\n\t * so the block cache and write buffers draw from a single pool. During\n\t * write bursts the cache shrinks to make room for memtables; once\n\t * memtables flush, the cache can grow back into the reclaimed space.\n\t *\n\t * Has no effect when the block cache is disabled (size 0) or\n\t * `writeBufferManagerSize` is 0. Must be set on the same `config()` call\n\t * that first enables the manager — changing it after the manager has been\n\t * created has no effect on the running instance.\n\t *\n\t * @default false\n\t */\n\twriteBufferManagerCostToCache?: boolean;\n\t/**\n\t * When `true`, writes are stalled once the manager's `buffer_size` is\n\t * exceeded, providing a hard cap on memtable memory. When `false`,\n\t * memtables are allowed to grow past the limit and flushes are simply\n\t * scheduled more aggressively. Off by default to favor write throughput\n\t * over hard memory bounding.\n\t *\n\t * @default false\n\t */\n\twriteBufferManagerAllowStall?: boolean;\n};\n\nconst nativeExtRE = /\\.node$/;\nconst req = createRequire(import.meta.url);\n\n/**\n * Locates the native binding in the `build` directory, then the `prebuilds`\n * directory.\n *\n * @returns The path to the native binding.\n */\nfunction locateBinding(): string {\n\tconst baseDir = dirname(dirname(fileURLToPath(import.meta.url)));\n\n\t// check build directory\n\tfor (const type of ['Release', 'Debug'] as const) {\n\t\ttry {\n\t\t\tconst dir = join(baseDir, 'build', type);\n\t\t\tconst files = readdirSync(dir);\n\t\t\tfor (const file of files) {\n\t\t\t\tif (nativeExtRE.test(file)) {\n\t\t\t\t\treturn resolve(dir, file);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t/* v8 ignore next -- @preserve */\n\t\t} catch {}\n\t}\n\n\t// determine the Linux C runtime\n\tlet runtime = '';\n\tif (process.platform === 'linux') {\n\t\tlet isMusl = false;\n\t\ttry {\n\t\t\tisMusl = readFileSync('/usr/bin/ldd', 'utf8').includes('musl');\n\t\t} catch {\n\t\t\t// `/usr/bin/ldd` likely doesn't exist\n\t\t\tif (typeof process.report?.getReport === 'function') {\n\t\t\t\tprocess.report.excludeEnv = true;\n\t\t\t\tconst report = process.report.getReport() as unknown as {\n\t\t\t\t\theader?: { glibcVersionRuntime?: string };\n\t\t\t\t\tsharedObjects?: string[];\n\t\t\t\t};\n\t\t\t\tisMusl =\n\t\t\t\t\t(!report?.header || !report.header.glibcVersionRuntime) &&\n\t\t\t\t\tArray.isArray(report?.sharedObjects) &&\n\t\t\t\t\treport.sharedObjects.some(\n\t\t\t\t\t\t(obj) => obj.includes('libc.musl-') || obj.includes('ld-musl-')\n\t\t\t\t\t);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tisMusl =\n\t\t\t\t\tisMusl ||\n\t\t\t\t\texecSync('ldd --version', {\n\t\t\t\t\t\tencoding: 'utf8',\n\t\t\t\t\t\tstdio: 'pipe',\n\t\t\t\t\t}).includes('musl');\n\t\t\t} catch {\n\t\t\t\t// ldd may not exist on some systems such as Docker Hardened Images\n\t\t\t}\n\t\t}\n\t\truntime = isMusl ? '-musl' : '-glibc';\n\t}\n\n\t// the following lines are non-trivial to test, so we'll ignore them\n\t/* v8 ignore next 10 -- @preserve */\n\n\t// check node_modules\n\ttry {\n\t\treturn require.resolve(`@harperfast/rocksdb-js-${process.platform}-${process.arch}${runtime}`);\n\t} catch {}\n\n\tthrow new Error('Unable to locate rocksdb-js native binding');\n}\n\nexport type RegistryStatusTransaction = {\n\t/** The transaction id assigned by the database descriptor. */\n\tid: number;\n\t/** Milliseconds since the transaction handle was created. */\n\tageMs: number;\n};\n\nexport type RegistryStatusDB = {\n\tpath: string;\n\trefCount: number;\n\tcolumnFamilies: string[];\n\ttransactions: number;\n\t/**\n\t * One entry per live transaction handle. An `ageMs` beyond any plausible request lifetime,\n\t * against a nonzero `rocksdb.num-snapshots`, identifies a handle holding back reclamation for\n\t * its whole database.\n\t */\n\ttransactionDetails: RegistryStatusTransaction[];\n\tclosables: number;\n\tlocks: number;\n\tuserSharedBuffers: number;\n\tlistenerCallbacks: number;\n};\n\nexport type RegistryStatus = RegistryStatusDB[];\n\nconst bindingPath = locateBinding();\n// console.log(`Loading binding from ${bindingPath}`);\nconst binding = req(bindingPath);\n\n/**\n * The native `BackgroundError` constructor (a real `Error` subclass). Exported\n * as both a value — for `err instanceof BackgroundError` — and, via declaration\n * merging with the interface above, a type. Instances are produced by the\n * `'error'` event and `db.getLastError()`; consumers rarely construct their own.\n * The `details` param is required and typed to the instance fields so a bare\n * `new BackgroundError()` (which would omit `severity` / `writesDisabled` / …)\n * is a type error.\n */\nexport const BackgroundError: new (\n\tdetails: Pick<\n\t\tBackgroundError,\n\t\t'message' | 'severity' | 'severityName' | 'writesDisabled' | 'reason' | 'reasonName'\n\t> & { type?: string }\n) => BackgroundError = binding.BackgroundError;\n\nexport const config: (options: RocksDatabaseConfig) => void = binding.config;\nexport const FRESH_VERSION_FLAG: number = binding.constants.FRESH_VERSION_FLAG;\nexport const addGlobalListener: (event: string, callback: (...args: any[]) => void) => void =\n\tbinding.addListener;\nexport const removeGlobalListener: (event: string, callback: (...args: any[]) => void) => boolean =\n\tbinding.removeListener;\nexport const globalListenerCount: (event: string) => number = binding.listenerCount;\nexport const globalNotify: (event: string, args?: any[]) => boolean = binding.notify;\nexport const constants: {\n\tALWAYS_CREATE_NEW_BUFFER_FLAG: number;\n\tNOT_IN_MEMORY_CACHE_FLAG: number;\n\tONLY_IF_IN_MEMORY_CACHE_FLAG: number;\n\tPOPULATE_VERSION_FLAG: number;\n\tFRESH_VERSION_FLAG: number;\n\t/**\n\t * Producer flag in a value's metadata word (4 big-endian bytes at offset 8, top byte `0x0E`,\n\t * low 24 bits flags), declaring that this version does NOT uniquely identify the value —\n\t * the producer has stored more than one distinct value under it.\n\t *\n\t * Set it and the VerificationTable stops treating version equality as evidence for this value:\n\t * a read never answers `FRESH_VERSION_FLAG` for it and never publishes its version to a slot,\n\t * so a consumer holding a differing cached copy at that version cannot have it confirmed.\n\t * Clear it again on the next write that gives the value a version of its own.\n\t *\n\t * Read only from values in a column family that opted into the verification table. Do not call\n\t * `populateVersion()` for a marked version: that explicit primitive never sees the value and\n\t * cannot enforce this flag.\n\t */\n\tVERSION_NOT_UNIQUE_FLAG: number;\n\t/**\n\t * Sentinel value resolved (not rejected) by `commit()` when\n\t * `coordinatedRetry: true` and the transaction encountered an IsBusy\n\t * conflict. JS should retry the transaction body immediately.\n\t */\n\tRETRY_NOW_VALUE: number;\n\tTRANSACTION_LOG_TOKEN: number;\n\tTRANSACTION_LOG_ENTRY_HEADER_SIZE: number;\n\tTRANSACTION_LOG_FILE_HEADER_SIZE: number;\n\tITERATOR_REVERSE_FLAG: number;\n\tITERATOR_INCLUSIVE_END_FLAG: number;\n\tITERATOR_EXCLUSIVE_START_FLAG: number;\n\tITERATOR_INCLUDE_VALUES_FLAG: number;\n\tITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG: number;\n\tITERATOR_CONTEXT_IS_TRANSACTION_FLAG: number;\n\tITERATOR_RESULT_DONE: number;\n\tITERATOR_RESULT_FAST: number;\n} = binding.constants;\n/**\n * The friendly names of every compression algorithm compiled into the loaded\n * RocksDB native binding, e.g. `['none', 'snappy', 'lz4', 'zstd']`. The set is\n * fixed for a given binary (it depends on which compression libraries RocksDB\n * was linked against), so this is a static list. `'none'` (no compression) is\n * always present. Use it to validate a `compression` option or to pick an\n * algorithm that is actually available at runtime.\n */\nexport const supportedCompression: readonly string[] = Object.freeze(\n\tbinding.supportedCompression as string[]\n);\nexport const NativeDatabase: NativeDatabase = binding.Database;\nexport const NativeIterator: typeof NativeIteratorCls = binding.Iterator;\nexport const NativeTransaction: NativeTransaction = binding.Transaction;\nexport const TransactionLog: TransactionLog = binding.TransactionLog;\nexport const registryStatus: () => RegistryStatus = binding.registryStatus;\nexport const shutdown: () => void = binding.shutdown;\nexport const currentThreadId: () => number = binding.currentThreadId;\n\n/**\n * Advises the kernel that the file-backed pages of every mapped transaction log\n * are cold (Linux MADV_COLD), so they are reclaimed first under memory pressure\n * without being freed — useful during replication catch-up, where a full read of\n * the logs would otherwise inflate the container's reclaimable cache toward its\n * cgroup limit. No-op on kernels < 5.4, macOS, and Windows.\n *\n * The transaction log registry is a process-global singleton shared across all\n * worker threads, so a single call cools every worker's maps. Call it on an\n * interval from one thread (e.g. an `unref()`ed timer on the main thread).\n *\n * @returns the number of maps cooled and total file-backed bytes advised.\n */\nexport const coolTransactionLogs: () => { maps: number; bytes: number } =\n\tbinding.coolTransactionLogs;\n\n/**\n * Number of live transaction-log memory maps across the process. Internal —\n * used by tests to verify that releasing a frozen log's external buffer unmaps\n * the underlying mapping rather than leaving it retained.\n */\nexport const transactionLogMapCount: () => number = binding.transactionLogMapCount;\n\n/**\n * Test-only: force the next `count` transaction commits to fail with TryAgain (rolled back, so\n * no data is committed), reproducing a stranded-snapshot conflict deterministically. Pass 0 to\n * disarm. Used by the ERR_TRY_AGAIN retry regression test.\n */\nexport const forceTryAgainForTesting: (count: number) => void = binding.forceTryAgainForTesting;\n\n/**\n * Creates a native file lock using the specified file path (`flock` on POSIX,\n * `LockFileEx` on Windows), creating the file and any missing parent\n * directories. Exclusive by default; pass `shared` for a shared (reader) lock\n * that coexists with other shared holders but conflicts with an exclusive\n * holder in either direction. Returns an opaque non-zero token to pass to\n * `fileLockRelease`, or `0` if a conflicting holder — in any process,\n * container, or worker thread — currently has it. Throws on a hard error. The\n * OS handle is owned entirely in native code (no fd crosses into JS), and the\n * kernel releases the lock when the handle closes, including on process death.\n */\nexport const tryFileLock: (file: string, shared?: boolean) => number = binding.tryFileLock;\n\n/**\n * Releases a file lock acquired via `tryFileLock`. A no-op for\n * token `0` or an unknown token.\n */\nexport const fileLockRelease: (token: number) => void = binding.fileLockRelease;\n\n// Module-level backup management functions. These operate on a backup directory\n// and do not require an open database. Wrapped by the `backups` namespace in\n// `backup.ts`; creating a backup is a `RocksDatabase` instance method.\nexport const nativeBackupRestore: (\n\tresolve: ResolveCallback<void>,\n\treject: RejectCallback,\n\tbackupDir: string,\n\tdbDir: string,\n\twalDir: string,\n\toptions?: {\n\t\tbackupId?: number;\n\t\tkeepLogFiles?: boolean;\n\t\tmode?: RestoreOptions['mode'];\n\t}\n) => void = binding.backupRestore;\nexport const nativeBackupList: (\n\tresolve: ResolveCallback<BackupInfo[]>,\n\treject: RejectCallback,\n\tbackupDir: string\n) => void = binding.backupList;\nexport const nativeBackupDelete: (\n\tresolve: ResolveCallback<void>,\n\treject: RejectCallback,\n\tbackupDir: string,\n\tbackupId: number\n) => void = binding.backupDelete;\nexport const nativeBackupPurge: (\n\tresolve: ResolveCallback<void>,\n\treject: RejectCallback,\n\tbackupDir: string,\n\tkeepCount: number\n) => void = binding.backupPurge;\nexport const nativeBackupVerify: (\n\tresolve: ResolveCallback<void>,\n\treject: RejectCallback,\n\tbackupDir: string,\n\tbackupId: number,\n\tverifyWithChecksum: boolean\n) => void = binding.backupVerify;\n\n// Module-level transaction log store validation. Operates on a store directory\n// (a closed database's store or a backup snapshot) and does not require an open\n// database. Wrapped by `validateTransactionLogStore` in\n// `validate-transaction-log.ts`.\nexport const nativeValidateTransactionLog: (\n\tresolve: ResolveCallback<TransactionLogStoreValidation>,\n\treject: RejectCallback,\n\tpath: string,\n\tstrict: boolean\n) => void = binding.validateTransactionLog;\n\nexport const stats: {\n\tStatsLevel: {\n\t\tDisableAll: number;\n\t\tExceptTickers: number;\n\t\tExceptHistogramOrTimers: number;\n\t\tExceptTimers: number;\n\t\tExceptDetailedTimers: number;\n\t\tExceptTimeForMutex: number;\n\t\tAll: number;\n\t};\n} = binding.stats;\n\nexport const version: string = binding.version;\n","import { nativeValidateTransactionLog } from './load-binding.ts';\n\n/**\n * The validation result for a single transaction log file within a store, as\n * returned by {@link validateTransactionLogStore}.\n */\nexport interface TransactionLogFileValidation {\n\t/** File name relative to the store directory, e.g. `\"3.txnlog\"`. */\n\tfile: string;\n\t/** Sequence number parsed from the file name. */\n\tsequence: number;\n\t/** On-disk file size in bytes. */\n\tsize: number;\n\t/** Number of well-formed entry frames. */\n\tentries: number;\n\t/** End offset of the validly framed data (header + well-formed entries). */\n\tvalidBytes: number;\n\t/** `true` when `errors` is empty. */\n\tvalid: boolean;\n\t/**\n\t * Conditions that make the file invalid: a bad/missing header, an\n\t * unsupported version, or a mid-file framing break. With `strict`, a torn\n\t * tail is also reported here.\n\t */\n\terrors: string[];\n\t/**\n\t * Conditions that do not invalidate the file: a torn tail (recoverable —\n\t * open-time recovery truncates it without losing committed entries) and\n\t * per-entry anomalies such as suspicious timestamps or undefined flag bits.\n\t */\n\twarnings: string[];\n}\n\n/**\n * The result of validating a transaction log store directory, as returned by\n * {@link validateTransactionLogStore}.\n */\nexport interface TransactionLogStoreValidation {\n\t/** The validated store directory. */\n\tpath: string;\n\t/**\n\t * `true` when there are no store-level errors and every log file is valid.\n\t */\n\tvalid: boolean;\n\t/** Per-file validation results, ordered by sequence number. */\n\tfiles: TransactionLogFileValidation[];\n\t/**\n\t * Store-level errors: malformed file names, an unreadable file, or a\n\t * corrupt `txn.state`.\n\t */\n\terrors: string[];\n\t/**\n\t * Store-level warnings: sequence gaps, unexpected directory entries, or an\n\t * implausible `txn.state` flushed position.\n\t */\n\twarnings: string[];\n}\n\n/**\n * Options for {@link validateTransactionLogStore}.\n */\nexport interface ValidateTransactionLogStoreOptions {\n\t/**\n\t * Report conditions that indicate an incomplete snapshot — a torn tail, a\n\t * sequence gap, or a `txn.state` flushed position beyond the newest log\n\t * file or beyond its file's actual size — as errors instead of warnings. A\n\t * torn tail on a live store is a normal crash artifact that open-time\n\t * recovery truncates, but a backup snapshot captures every surviving file\n\t * on committed entry boundaries and must be clean end to end —\n\t * `backups.verify()` validates snapshots with `strict: true`. Defaults to\n\t * `false`.\n\t */\n\tstrict?: boolean;\n}\n\n/**\n * Validates a transaction log store directory: every `<sequence>.txnlog` file\n * is checked for a valid header (token, version) and intact v1 entry framing\n * (using the same scan as open-time crash recovery), file-name and sequence\n * continuity are checked, and the `txn.state` side file (when present) is\n * checked for shape and a plausible flushed position. The result reports\n * per-file entry counts, errors, and warnings; it does not throw when the\n * store is invalid — check `result.valid`.\n *\n * Runs entirely in native code on a worker thread and does not require (or\n * open) a database, so it works on the store of a closed database and on the\n * per-backup snapshots under `<backupDir>/transaction_logs/<backupId>/` alike.\n *\n * Validating a store that is being actively appended to can spuriously report\n * a torn tail for the current log file — the tail of an in-flight append is\n * indistinguishable from a crash artifact.\n *\n * Rejects if `path` does not exist or is not a directory (a bad argument, as\n * opposed to an invalid store).\n *\n * @param path The store directory, e.g. `<dbDir>/transaction_logs/<name>`.\n * @param options Validation options.\n *\n * @example\n * ```typescript\n * import { validateTransactionLogStore } from '@harperfast/rocksdb-js';\n *\n * const result = await validateTransactionLogStore('/path/to/db/transaction_logs/mylog');\n * if (!result.valid) {\n * for (const file of result.files) {\n * console.error(file.file, file.errors);\n * }\n * }\n * ```\n */\nexport function validateTransactionLogStore(\n\tpath: string,\n\toptions?: ValidateTransactionLogStoreOptions\n): Promise<TransactionLogStoreValidation> {\n\treturn new Promise((resolve, reject) =>\n\t\tnativeValidateTransactionLog(resolve, reject, path, options?.strict ?? false)\n\t);\n}\n","import {\n\tnativeBackupDelete,\n\tnativeBackupList,\n\tfileLockRelease,\n\ttryFileLock,\n\tnativeBackupPurge,\n\tnativeBackupRestore,\n\tnativeBackupVerify,\n} from './load-binding.ts';\nimport { validateTransactionLogStore } from './validate-transaction-log.ts';\nimport { access, cp, mkdir, readdir, rm } from 'node:fs/promises';\nimport { isAbsolute, join, relative, resolve as resolvePath, sep } from 'node:path';\n\n/** Subdirectory (under a backup directory) holding per-backup transaction log snapshots. */\nconst TRANSACTION_LOGS_DIRNAME = 'transaction_logs';\n\n/** Non-blocking existence check (`fs.existsSync` would block the event loop). */\nasync function exists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Runs `fn` while holding a native file lock for `backupDir`, releasing it when\n * `fn` settles. The lock is exclusive by default — used by the writable-engine\n * operations `backups.delete` and `backups.purge`; backup creation\n * (`Store.backup`) takes the same exclusive lock on the same file natively\n * inside `Database::Backup` (see `runCreateBackup` in\n * `src/binding/database/backup.cpp`), where the backup directory is also\n * created. Throws immediately (without running `fn`) if the backup directory\n * is missing — `tryFileLock` creates missing parents, but `delete`/`purge`/\n * `restore` on a nonexistent directory is a caller error and must not conjure\n * an empty one — or if a conflicting holder has the directory lock.\n *\n * `backups.restore` holds the lock in `shared` mode for its source read:\n * shared holders coexist (concurrent restores are safe), but a writer's\n * exclusive acquisition rejects while a restore is in flight — and vice versa.\n * Without this, a `purge`/`delete` racing a restore can delete the very files\n * the restore is copying, after the restore's default `purgeAllFiles` mode has\n * already wiped the destination — failing the restore with no fallback. A\n * rejected writer, by contrast, just retries later.\n *\n * The remaining read-only operations (`list`, `verify`) use\n * `BackupEngineReadOnly` and are not locked: concurrent readers are safe, and\n * locking them would make cheap listings reject during a long backup. Running\n * them concurrently with a `delete`/`purge` on the same directory is a\n * caller-managed hazard, matching RocksDB's one-writable-engine-per-dir model.\n *\n * RocksDB only serializes work within a single `BackupEngine` instance and has\n * no lock on the backup directory itself. Two writable engines — in any\n * processes — creating/deleting/purging backups in the same directory\n * concurrently race on the per-backup staging directory and both fail,\n * potentially leaving the directory with no usable backup. An in-memory lock\n * cannot prevent this across processes, so the lock lives on disk: a kernel\n * advisory lock (`flock` on POSIX, `LockFileEx` on Windows) held on a\n * `.backup.lock` file at the directory root.\n *\n * The lock is taken entirely in native code (`tryFileLock`), which opens,\n * locks, and later closes the file's OS handle without ever exposing a\n * descriptor to JS — the addon statically links its own C runtime, so a\n * Node/libuv fd is not usable across that boundary. The kernel owning the lock\n * buys two properties a pidfile cannot:\n *\n * - No staleness heuristic. The lock is released when the holder's handle closes\n * — normal release, crash, `kill -9`, container exit — so there is nothing to\n * reclaim and no liveness check.\n * - True cross-context exclusion. The lock conflicts across processes, containers\n * sharing a volume (same kernel), and `worker_threads`.\n *\n * The lock file is never deleted, only locked and unlocked; an unlocked, empty\n * `.backup.lock` at the directory root is the steady state.\n */\nexport async function withBackupDirLock<T>(\n\tbackupDir: string,\n\tfn: () => Promise<T>,\n\toptions?: { shared?: boolean }\n): Promise<T> {\n\tif (!(await exists(backupDir))) {\n\t\tthrow new Error(`Backup directory does not exist: ${backupDir}`);\n\t}\n\tconst token = tryFileLock(join(backupDir, '.backup.lock'), options?.shared === true);\n\tif (token === 0) {\n\t\tthrow new Error(`Backup directory is locked: ${backupDir}`);\n\t}\n\ttry {\n\t\treturn await fn();\n\t} finally {\n\t\tfileLockRelease(token);\n\t}\n}\n\n/**\n * Throws if `backupDir` resolves to the database directory itself or any path\n * beneath it. Backing up into the live database directory would write backup\n * files (the `.backup.lock`, `meta/`, `shared/`, `private/` subtrees) on top of\n * RocksDB's own files, and every subsequent backup would recursively capture\n * the prior ones. Both paths are resolved first so trailing slashes and\n * relative/absolute variants of the same location cannot slip past the check.\n *\n * Only the \"backup dir at or under the database dir\" direction is rejected —\n * the case the user hits by pointing a backup at `<db>` or `<db>/backups`. The\n * reverse (a database nested under the backup dir) is left to the caller: a\n * backup engine writes into named subtrees, not on top of arbitrary sibling\n * files, so it does not clobber the database in place.\n *\n * On case-insensitive filesystems `<db>` and `<db>/../DB/backup` are the same\n * directory on disk, but `relative()` compares case-sensitively and would call\n * the second one \"outside\". We case-fold both paths on the platforms whose\n * default filesystem is case-insensitive (macOS, Windows) so a casing\n * difference cannot slip a backup into the database directory. This is a\n * platform heuristic, not a per-volume probe (a case-sensitive macOS/Windows\n * volume exists), so it can over-reject a legitimately differently-cased\n * sibling there — the safe direction for a guard against clobbering the live\n * database.\n */\nexport function assertBackupDirOutsideDatabase(dbPath: string, backupDir: string): void {\n\tlet resolvedDb = resolvePath(dbPath);\n\tlet resolvedBackup = resolvePath(backupDir);\n\tif (process.platform === 'win32' || process.platform === 'darwin') {\n\t\tresolvedDb = resolvedDb.toLowerCase();\n\t\tresolvedBackup = resolvedBackup.toLowerCase();\n\t}\n\tconst rel = relative(resolvedDb, resolvedBackup);\n\tconst outside = rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel);\n\tif (!outside) {\n\t\tthrow new Error(\n\t\t\t`Backup directory must not be inside the database directory: ${backupDir} is at or within ${dbPath}`\n\t\t);\n\t}\n}\n\n/**\n * Options for creating a backup via `db.backup()`.\n *\n * Backups are whole-database: every column family, the manifest, and (unless\n * `backupLogFiles` is disabled) the write-ahead log are captured. A backup is\n * not scoped to an individual `Store`.\n */\nexport interface BackupOptions {\n\t/**\n\t * Include write-ahead log files in the backup. Defaults to `true`.\n\t */\n\tbackupLogFiles?: boolean;\n\n\t/**\n\t * Preflight the destination volume and reject the backup when it lacks room.\n\t * Defaults to `true`. The rejection is an I/O error whose message reports the\n\t * available and required bytes (it is not distinguishable by an `err.code`).\n\t *\n\t * The required size is estimated conservatively as a *full* copy of the\n\t * database's live files, plus the transaction-log snapshot when\n\t * `transactionLogs` is enabled (a backup only ever copies files, so this can\n\t * never under-estimate the bytes written). For incremental backups to a\n\t * right-sized volume this may over-reject — set `false` to skip the check in\n\t * that case. The check also self-disables when free space is unknowable (e.g.\n\t * some network filesystems report 0), so it never blocks a backup on an\n\t * untrustworthy number.\n\t *\n\t * Only applies to directory-target backups; the streaming backup path is\n\t * unaffected.\n\t */\n\tcheckDiskSpace?: boolean;\n\n\t/**\n\t * Flush the memtable before backing up. Defaults to `true` when the database\n\t * was opened with `disableWAL` (otherwise unflushed data would be lost from\n\t * the backup), and `false` otherwise.\n\t */\n\tflushBeforeBackup?: boolean;\n\n\t/**\n\t * Number of background threads used to copy files. Defaults to `1`.\n\t */\n\tmaxBackgroundOperations?: number;\n\n\t/**\n\t * Arbitrary application metadata stored with the backup and returned by\n\t * `backups.list()`.\n\t */\n\tmetadata?: string;\n\n\t/**\n\t * Distinguish shared files by checksum to avoid collisions across databases.\n\t * Defaults to `true`. Only relevant when `shareTableFiles` is enabled.\n\t */\n\tshareFilesWithChecksum?: boolean;\n\n\t/**\n\t * Share table/blob files between backups in the same directory to enable\n\t * incremental backups. Defaults to `true`.\n\t */\n\tshareTableFiles?: boolean;\n\n\t/**\n\t * `fsync` backup files — including the transaction log snapshot when\n\t * `transactionLogs` is enabled — for crash consistency. Defaults to `true`.\n\t */\n\tsync?: boolean;\n\n\t/**\n\t * Snapshot the transaction log store into\n\t * `<backupDir>/transaction_logs/<backupId>/`. Defaults to `false`. This is an\n\t * all-or-nothing snapshot per backup (not incremental); `backups.delete()` and\n\t * `backups.purge()` remove the corresponding log snapshots, and\n\t * `backups.restore()` restores them into the database directory.\n\t *\n\t * The snapshot is staged and atomically renamed into place after every file\n\t * is copied (and fsynced, per `sync`), so a crash mid-backup can never leave\n\t * a partial snapshot: a backup id either has its complete log snapshot or\n\t * none at all.\n\t *\n\t * The log snapshot is captured just after the RocksDB engine snapshot, so it\n\t * may include entries committed between the two — the restored logs can run\n\t * slightly ahead of the restored key-value data, never behind it. That bias\n\t * is safe for redo-style logs that are replayed against the restored data.\n\t */\n\ttransactionLogs?: boolean;\n}\n\n/**\n * The level of incremental restore to perform.\n *\n * - `purgeAllFiles` (default): purge the destination directory and restore all\n * files from the backup. Destructive but always correct.\n * - `keepLatestDbSessionIdFiles`: efficiently restore a healthy database,\n * reusing existing files that match the backup.\n * - `verifyChecksum`: reuse existing destination files whose checksums match the\n * backup, replacing only mismatched/corrupt files.\n */\nexport type RestoreMode = 'purgeAllFiles' | 'keepLatestDbSessionIdFiles' | 'verifyChecksum';\n\n/**\n * Options for restoring a backup via `backups.restore()`.\n */\nexport interface RestoreOptions {\n\t/**\n\t * The backup id to restore. Defaults to the latest non-corrupt backup.\n\t */\n\tbackupId?: number;\n\n\t/**\n\t * Directory to restore write-ahead log files into. Defaults to the database\n\t * directory.\n\t */\n\twalDir?: string;\n\n\t/**\n\t * Keep existing log files in `walDir` rather than overwriting them. Defaults\n\t * to `false`.\n\t */\n\tkeepLogFiles?: boolean;\n\n\t/**\n\t * The restore strategy. Defaults to `purgeAllFiles`, which is destructive.\n\t */\n\tmode?: RestoreMode;\n}\n\n/**\n * Information about a single backup, as returned by `backups.list()`.\n */\nexport interface BackupInfo {\n\t/** The backup id (monotonically increasing integer). */\n\tbackupId: number;\n\t/** Creation time in seconds since the epoch. */\n\ttimestamp: number;\n\t/** Total size in bytes of the backed-up file payloads. */\n\tsize: number;\n\t/** Number of files in the backup (some may be shared with other backups). */\n\tnumberFiles: number;\n\t/** Application metadata supplied when the backup was created. */\n\tappMetadata: string;\n}\n\n/**\n * Removes `<backupDir>/transaction_logs/<id>` subtrees whose backup id no longer\n * corresponds to a surviving backup. Called after a `purge` (which holds the\n * backup-dir lock); a no-op when no transaction logs were backed up. Self-healing:\n * it drops every log subtree without a live backup. Note the surviving set comes\n * from `nativeBackupList`, which omits corrupt backups — a still-present but\n * corrupt backup's logs may be pruned (acceptable: it cannot be restored anyway).\n * This also sweeps `.staging-*` leftovers from a crashed backup process (a\n * staging name never matches a live backup id); backup creation sweeps them\n * natively as well, under the backup-dir lock.\n */\nasync function pruneOrphanedTransactionLogs(backupDir: string): Promise<void> {\n\tconst logsRoot = join(backupDir, TRANSACTION_LOGS_DIRNAME);\n\tlet ids: string[];\n\ttry {\n\t\tids = await readdir(logsRoot);\n\t} catch (err) {\n\t\tif ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\treturn; // no transaction logs were backed up\n\t\t}\n\t\tthrow err;\n\t}\n\n\tconst list = await new Promise<BackupInfo[]>((resolve, reject) =>\n\t\tnativeBackupList(resolve, reject, backupDir)\n\t);\n\tconst surviving = new Set(list.map((info) => String(info.backupId)));\n\n\tawait Promise.all(\n\t\tids\n\t\t\t.filter((id) => !surviving.has(id))\n\t\t\t.map((id) => rm(join(logsRoot, id), { recursive: true, force: true }))\n\t);\n}\n\n/**\n * Restores the transaction log snapshot for the restored backup into\n * `<dbDir>/transaction_logs/`, wiping the destination first so that restoring an\n * older backup over a newer one cannot leave stale (newer) log files behind.\n *\n * Only acts when THIS backup actually captured logs: if the restored id has no\n * snapshot, the destination is left untouched. Wiping unconditionally would\n * destroy on-disk logs that a mixed-mode (`transactionLogs:false`) backup never\n * managed.\n *\n * Offline only: the files are picked up when the database is next opened. mtimes\n * are preserved because the store derives file age (rotation/retention) from\n * mtime — a fresh mtime would break retention.\n */\nasync function restoreTransactionLogs(\n\tbackupDir: string,\n\tdbDir: string,\n\tbackupId?: number\n): Promise<void> {\n\tconst logsRoot = join(backupDir, TRANSACTION_LOGS_DIRNAME);\n\tif (!(await exists(logsRoot))) {\n\t\treturn; // this backup directory has no transaction log snapshots\n\t}\n\n\t// Resolve the restored backup id (the latest, when unspecified).\n\tlet id = backupId;\n\tif (id === undefined) {\n\t\tconst list = await new Promise<BackupInfo[]>((resolve, reject) =>\n\t\t\tnativeBackupList(resolve, reject, backupDir)\n\t\t);\n\t\tif (list.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tid = Math.max(...list.map((info) => info.backupId));\n\t}\n\n\tconst logsSrc = join(logsRoot, String(id));\n\tif (!(await exists(logsSrc))) {\n\t\t// The restored backup captured no logs — do not touch the destination's\n\t\t// existing transaction logs.\n\t\treturn;\n\t}\n\n\t// This backup has logs: wipe the destination, then restore its snapshot.\n\tconst logsDest = join(dbDir, TRANSACTION_LOGS_DIRNAME);\n\tawait rm(logsDest, { recursive: true, force: true });\n\tawait cp(logsSrc, logsDest, { recursive: true, preserveTimestamps: true });\n}\n\n/**\n * Backup management operations that act on a backup directory and do not\n * require an open database. To create a backup, use the `db.backup()` instance\n * method instead (it needs a live database for a consistent snapshot).\n *\n * @example\n * ```typescript\n * import { backups } from '@harperfast/rocksdb-js';\n *\n * const id = await db.backup('/path/to/backups');\n * db.close();\n * await backups.restore('/path/to/backups', '/path/to/restored-db');\n * ```\n */\nexport const backups = {\n\t/**\n\t * Restores a database from a backup directory into a (closed) database\n\t * directory. The default mode purges the destination directory, so it must\n\t * not point at a live database.\n\t *\n\t * Holds the backup directory lock in shared mode for the duration: multiple\n\t * restores can read concurrently, but a writer (`db.backup()`, `delete`,\n\t * `purge`) rejects while a restore is in flight rather than deleting files\n\t * out from under it — and a restore rejects while a writer holds the lock.\n\t *\n\t * The shared lock needs no write access to `backupDir`, so restoring from a\n\t * read-only backup directory (immutable/WORM store, read-only-mounted volume)\n\t * works: the lock is taken on an existing `.backup.lock` read-only, degrading\n\t * to a no-op only when the media is read-only for every process (`EROFS`). A\n\t * mere permission denial hard-fails instead — it doesn't prove a privileged\n\t * writer isn't running.\n\t */\n\tasync restore(backupDir: string, dbDir: string, options?: RestoreOptions): Promise<void> {\n\t\t// Normalize before comparing so trailing slashes or relative/absolute\n\t\t// variants of the same directory can't slip past the guard and let a\n\t\t// destructive restore purge the backup directory itself.\n\t\tif (resolvePath(backupDir) === resolvePath(dbDir)) {\n\t\t\tthrow new Error('Backup directory and database directory must be different');\n\t\t}\n\n\t\treturn withBackupDirLock(\n\t\t\tbackupDir,\n\t\t\tasync () => {\n\t\t\t\tconst walDir = options?.walDir ?? dbDir;\n\t\t\t\tawait mkdir(dbDir, { recursive: true });\n\t\t\t\tif (walDir !== dbDir) {\n\t\t\t\t\tawait mkdir(walDir, { recursive: true });\n\t\t\t\t}\n\n\t\t\t\tawait new Promise<void>((resolve, reject) =>\n\t\t\t\t\tnativeBackupRestore(resolve, reject, backupDir, dbDir, walDir, {\n\t\t\t\t\t\tbackupId: options?.backupId,\n\t\t\t\t\t\tkeepLogFiles: options?.keepLogFiles,\n\t\t\t\t\t\tmode: options?.mode,\n\t\t\t\t\t})\n\t\t\t\t);\n\n\t\t\t\t// Restore the transaction log snapshot (if this backup included one). Wipes\n\t\t\t\t// the destination first so an older restore leaves no newer log stragglers.\n\t\t\t\tawait restoreTransactionLogs(backupDir, dbDir, options?.backupId);\n\t\t\t},\n\t\t\t{ shared: true }\n\t\t);\n\t},\n\n\t/**\n\t * Lists the non-corrupt backups in a backup directory, ordered by id.\n\t */\n\tlist(backupDir: string): Promise<BackupInfo[]> {\n\t\treturn new Promise((resolve, reject) => nativeBackupList(resolve, reject, backupDir));\n\t},\n\n\t/**\n\t * Deletes a specific backup. Shared files are reference-counted and only\n\t * removed once no remaining backup references them.\n\t */\n\tasync delete(backupDir: string, backupId: number): Promise<void> {\n\t\treturn withBackupDirLock(backupDir, async () => {\n\t\t\tawait new Promise<void>((resolve, reject) =>\n\t\t\t\tnativeBackupDelete(resolve, reject, backupDir, backupId)\n\t\t\t);\n\t\t\t// Remove only this backup's own log snapshot: precise (no dependence on\n\t\t\t// the backup listing, which omits corrupt backups) and best-effort (the\n\t\t\t// backup is already gone, so a cleanup failure must not fail the delete).\n\t\t\ttry {\n\t\t\t\tawait rm(join(backupDir, TRANSACTION_LOGS_DIRNAME, String(backupId)), {\n\t\t\t\t\trecursive: true,\n\t\t\t\t\tforce: true,\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t// Best-effort: at worst an orphaned subtree remains for a later purge.\n\t\t\t}\n\t\t});\n\t},\n\n\t/**\n\t * Deletes all but the newest `keepCount` backups.\n\t */\n\tasync purge(backupDir: string, keepCount: number): Promise<void> {\n\t\treturn withBackupDirLock(backupDir, async () => {\n\t\t\tawait new Promise<void>((resolve, reject) =>\n\t\t\t\tnativeBackupPurge(resolve, reject, backupDir, keepCount)\n\t\t\t);\n\t\t\t// Best-effort: the backups are already purged, so a log-cleanup failure\n\t\t\t// must not fail the purge.\n\t\t\ttry {\n\t\t\t\tawait pruneOrphanedTransactionLogs(backupDir);\n\t\t\t} catch {\n\t\t\t\t// Best-effort orphan cleanup.\n\t\t\t}\n\t\t});\n\t},\n\n\t/**\n\t * Verifies a backup's file sizes, and optionally their checksums (which\n\t * requires reading all backed-up data).\n\t *\n\t * When the backup was created with `transactionLogs: true`, the backup's\n\t * transaction log snapshot (`<backupDir>/transaction_logs/<backupId>/`) is\n\t * also validated — every log file's header and entry framing must be intact\n\t * (snapshots are copied on committed entry boundaries, so even a torn tail\n\t * is a verification failure). Set `verifyTransactionLogs: false` to skip.\n\t */\n\tasync verify(\n\t\tbackupDir: string,\n\t\tbackupId: number,\n\t\toptions?: { verifyWithChecksum?: boolean; verifyTransactionLogs?: boolean }\n\t): Promise<void> {\n\t\tawait new Promise<void>((resolve, reject) =>\n\t\t\tnativeBackupVerify(resolve, reject, backupDir, backupId, options?.verifyWithChecksum ?? false)\n\t\t);\n\n\t\tif (options?.verifyTransactionLogs === false) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst logsDir = join(backupDir, TRANSACTION_LOGS_DIRNAME, String(backupId));\n\t\tif (!(await exists(logsDir))) {\n\t\t\t// this backup captured no transaction logs\n\t\t\treturn;\n\t\t}\n\n\t\tconst failures: string[] = [];\n\t\tfor (const entry of await readdir(logsDir, { withFileTypes: true })) {\n\t\t\tif (!entry.isDirectory()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst result = await validateTransactionLogStore(join(logsDir, entry.name), {\n\t\t\t\tstrict: true,\n\t\t\t});\n\t\t\tif (!result.valid) {\n\t\t\t\tconst details = [\n\t\t\t\t\t...result.errors,\n\t\t\t\t\t...result.files.flatMap((file) => file.errors.map((error) => `${file.file}: ${error}`)),\n\t\t\t\t];\n\t\t\t\tfailures.push(`${entry.name}: ${details.join('; ')}`);\n\t\t\t}\n\t\t}\n\t\tif (failures.length > 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`Backup ${backupId} transaction log verification failed: ${failures.join('\\n')}`\n\t\t\t);\n\t\t}\n\t},\n};\n","import type { CountEstimate, CountEstimateOptions } from './dbi.ts';\nimport type { Key } from './encoding.ts';\nimport type { Store } from './store.ts';\n\nexport interface CountEstimatorOptions extends CountEstimateOptions {}\n\n/**\n * Below this many traversed entries the observed density is too noisy to\n * calibrate with, so `estimate()` returns the raw statistical estimate.\n */\nconst CALIBRATION_MIN_TRAVERSED = 16;\nconst CALIBRATION_MIN_CONFIDENCE = 0.8;\n\n/**\n * Bounds on how far the observed-vs-estimated ratio may scale the remainder;\n * the statistical estimate can be arbitrarily wrong at data-block granularity\n * and an unclamped ratio would let one bad sample dominate.\n */\nconst CALIBRATION_MAX = 8;\n\n/**\n * Progressively refines a range key-count estimate as an iterator traverses\n * the range. The estimate starts as the pure statistical estimate\n * (`estimateCount`) and converges toward the exact count: the traversed\n * portion is exact, and the statistical estimate of the untraversed remainder\n * is calibrated by the observed ratio of actual-to-estimated entries over the\n * portion already traversed.\n *\n * The estimator never touches the iterator itself — the caller reports\n * progress with `advance(lastKey, count)` whenever it wants a checkpoint\n * (e.g. once per page), then reads `estimate()`. The caller owns the\n * progress contract: cursors must move monotonically through the range and\n * each entry must be reported once (a re-reported page inflates the count\n * undetectably). When traversal completes, call `finish()` so `estimate()`\n * returns the exact total instead of adding a block-granular remainder.\n *\n * Each `estimate()` checkpoint queries RocksDB statistics for the two range\n * segments (cost scales with the SSTs overlapping them, not with key count);\n * results are memoized per checkpoint, so repeated reads between `advance()`\n * calls are free.\n */\nexport class CountEstimator {\n\t#store: Store;\n\t#start: Key | Uint8Array | undefined;\n\t#end: Key | Uint8Array | undefined;\n\t#exclusiveStart: boolean;\n\t#inclusiveEnd: boolean;\n\t#reverse: boolean;\n\t#cursor: Key | Uint8Array | undefined;\n\t#traversed = 0;\n\t#finished = false;\n\t#memoized: CountEstimate | undefined;\n\n\tconstructor(store: Store, options?: CountEstimatorOptions) {\n\t\tthis.#store = store;\n\t\tthis.#reverse = options?.reverse ?? false;\n\t\tthis.#start = this.#reverse ? options?.end : options?.start;\n\t\tthis.#end = this.#reverse ? options?.start : options?.end;\n\t\tthis.#exclusiveStart = options?.exclusiveStart ?? this.#reverse;\n\t\tthis.#inclusiveEnd = options?.inclusiveEnd ?? this.#reverse;\n\t}\n\n\t/**\n\t * The number of entries reported traversed so far.\n\t */\n\tget traversed(): number {\n\t\treturn this.#traversed;\n\t}\n\n\t/**\n\t * Records that iteration has advanced through `count` more entries, ending\n\t * at `lastKey`. Pass `count: 0` when an empty page has no last key.\n\t */\n\tadvance(lastKey: Key | Uint8Array | undefined, count = 1): void {\n\t\tif (lastKey === undefined) {\n\t\t\tif (count !== 0) {\n\t\t\t\tthrow new Error('CountEstimator.advance requires lastKey when count is nonzero');\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis.#cursor = lastKey;\n\t\tthis.#traversed += count;\n\t\tthis.#memoized = undefined;\n\t}\n\n\t/**\n\t * Marks traversal of the range as complete: `estimate()` becomes the exact\n\t * traversed count.\n\t */\n\tfinish(): void {\n\t\tthis.#finished = true;\n\t}\n\n\t/**\n\t * Estimates the total number of entries in the full range: the exact\n\t * traversed count plus a calibrated statistical estimate of the remainder.\n\t * `confidence` is the exactness-weighted blend of the traversed portion\n\t * (exact) and the remainder's statistical confidence, so it approaches 1\n\t * as the exact portion grows (though a checkpoint can decrease when\n\t * calibration makes a large correction), and is exactly 1 after `finish()`.\n\t */\n\testimate(): CountEstimate {\n\t\tif (this.#finished) {\n\t\t\treturn { count: this.#traversed, confidence: 1 };\n\t\t}\n\t\tif (this.#memoized !== undefined) {\n\t\t\treturn { ...this.#memoized };\n\t\t}\n\t\tif (this.#cursor === undefined) {\n\t\t\tthis.#memoized = this.#store.estimateCount({\n\t\t\t\tstart: this.#start,\n\t\t\t\tend: this.#end,\n\t\t\t\texclusiveStart: this.#exclusiveStart,\n\t\t\t\tinclusiveEnd: this.#inclusiveEnd,\n\t\t\t});\n\t\t\treturn { ...this.#memoized };\n\t\t}\n\n\t\t// The cursor entry itself belongs to the traversed side, so the\n\t\t// remainder excludes it in both directions (an inclusive lower bound\n\t\t// forward would count it twice and block convergence). The range's own\n\t\t// bound flags stay with their original edge of the full range.\n\t\tconst traversedRange = this.#reverse\n\t\t\t? { start: this.#cursor, end: this.#end, inclusiveEnd: this.#inclusiveEnd }\n\t\t\t: {\n\t\t\t\t\tstart: this.#start,\n\t\t\t\t\texclusiveStart: this.#exclusiveStart,\n\t\t\t\t\tend: this.#cursor,\n\t\t\t\t\tinclusiveEnd: true,\n\t\t\t\t};\n\t\tconst remainingRange = this.#reverse\n\t\t\t? { start: this.#start, exclusiveStart: this.#exclusiveStart, end: this.#cursor }\n\t\t\t: {\n\t\t\t\t\tstart: this.#cursor,\n\t\t\t\t\texclusiveStart: true,\n\t\t\t\t\tend: this.#end,\n\t\t\t\t\tinclusiveEnd: this.#inclusiveEnd,\n\t\t\t\t};\n\n\t\tconst remainingEstimate = this.#store.estimateCount(remainingRange);\n\t\tlet remaining = remainingEstimate.count;\n\t\tlet calibrationConfidence = 1;\n\t\tif (this.#traversed >= CALIBRATION_MIN_TRAVERSED) {\n\t\t\tconst traversedEstimate = this.#store.estimateCount(traversedRange);\n\t\t\tif (\n\t\t\t\ttraversedEstimate.count >= CALIBRATION_MIN_TRAVERSED &&\n\t\t\t\ttraversedEstimate.confidence >= CALIBRATION_MIN_CONFIDENCE\n\t\t\t) {\n\t\t\t\tconst calibration = Math.min(\n\t\t\t\t\tCALIBRATION_MAX,\n\t\t\t\t\tMath.max(1 / CALIBRATION_MAX, this.#traversed / traversedEstimate.count)\n\t\t\t\t);\n\t\t\t\tremaining *= calibration;\n\t\t\t\tcalibrationConfidence = Math.min(calibration, 1 / calibration);\n\t\t\t}\n\t\t}\n\n\t\tconst count = Math.round(this.#traversed + remaining);\n\t\t// Cap below 1: only finish() (or an exact-by-construction range) may\n\t\t// claim exactness, even when rounding makes the remainder vanish.\n\t\tconst confidence =\n\t\t\tcount > 0\n\t\t\t\t? Math.min(\n\t\t\t\t\t\t0.999,\n\t\t\t\t\t\t(this.#traversed + calibrationConfidence * remainingEstimate.confidence * remaining) /\n\t\t\t\t\t\t\tcount\n\t\t\t\t\t)\n\t\t\t\t: Math.min(0.999, calibrationConfidence * remainingEstimate.confidence);\n\t\tthis.#memoized = { count, confidence };\n\t\treturn { ...this.#memoized };\n\t}\n}\n","export type MaybePromise<T> = T | Promise<T>;\n\nexport type MaybePromiseFunction<T> = () => MaybePromise<T>;\n\n/**\n * Parses a duration string into milliseconds.\n *\n * @param duration - The duration string to parse.\n * @returns The duration in milliseconds.\n *\n * @example\n * ```typescript\n * parseDuration('1s'); // 1000\n * parseDuration('1m'); // 60000\n * parseDuration('1h'); // 3600000\n * parseDuration('1d'); // 86400000\n * parseDuration('1ms'); // 1\n * parseDuration('1s 1ms'); // 1001\n * parseDuration('1m 1s'); // 61000\n * parseDuration('foo'); // throws error\n *\n * parseDuration(1000); // 1000\n * parseDuration(60000); // 60000\n * parseDuration(3600000); // 3600000\n * parseDuration(86400000); // 86400000\n * parseDuration(NaN); // throws error\n * ```\n */\nexport function parseDuration(duration: number | string): number {\n\tif (typeof duration === 'number') {\n\t\tif (isNaN(duration) || !isFinite(duration)) {\n\t\t\tthrow new Error(`Invalid duration: ${duration}`);\n\t\t}\n\t\treturn duration;\n\t}\n\n\tlet result = 0;\n\tfor (const part of duration.split(' ')) {\n\t\tconst m = part.match(/^(\\d+)\\s*(ms|s|m|h|d)?$/);\n\t\tif (!m) {\n\t\t\tthrow new Error(`Invalid duration: ${duration}`);\n\t\t}\n\n\t\tconst [, value, unit] = m;\n\t\tlet num = parseInt(value, 10);\n\t\tswitch (unit) {\n\t\t\tcase 's':\n\t\t\t\tnum *= 1000;\n\t\t\t\tbreak;\n\t\t\tcase 'm':\n\t\t\t\tnum *= 1000 * 60;\n\t\t\t\tbreak;\n\t\t\tcase 'h':\n\t\t\t\tnum *= 1000 * 60 * 60;\n\t\t\t\tbreak;\n\t\t\tcase 'd':\n\t\t\t\tnum *= 1000 * 60 * 60 * 24;\n\t\t\t\tbreak;\n\t\t}\n\t\tresult += num;\n\t}\n\treturn result;\n}\n\n/**\n * Helper function handling `MaybePromise` results.\n *\n * If the result originates from a function that could throw an error, wrap it\n * in a function so this function can catch any errors and use a unified error\n * handling mechanism.\n */\nexport function when<T>(\n\tsubject: MaybePromise<T> | MaybePromiseFunction<T>,\n\tcallback?: (value: T) => MaybePromise<T>,\n\terrback?: (reason: any) => T\n): MaybePromise<T> {\n\ttry {\n\t\tlet result: MaybePromise<T>;\n\n\t\tif (typeof subject === 'function') {\n\t\t\tresult = (subject as MaybePromiseFunction<T>)();\n\t\t} else {\n\t\t\tresult = subject;\n\t\t}\n\n\t\tif (result instanceof Promise) {\n\t\t\treturn result.then(callback, errback) as T;\n\t\t}\n\n\t\treturn callback ? callback(result as T) : (result as T);\n\t} catch (error) {\n\t\treturn errback ? errback(error) : Promise.reject(error);\n\t}\n}\n\n/**\n * Polyfill for `Promise.withResolvers`.\n *\n * Note: This can be removed once Node.js 18 and 20 are no longer supported.\n *\n * @returns A tuple of `resolve`, `reject`, and `promise`.\n */\nexport function withResolvers<T>(): {\n\tresolve: (value: T) => void;\n\treject: (reason: any) => void;\n\tpromise: Promise<T>;\n} {\n\tlet resolve, reject;\n\tconst promise = new Promise<T>((res, rej) => {\n\t\tresolve = res;\n\t\treject = rej;\n\t});\n\treturn { resolve, reject, promise };\n}\n","import type { BufferWithDataView, Key } from './encoding.ts';\nimport { FRESH_VERSION_FLAG } from './load-binding.ts';\nimport type { NativeTransaction, TransactionLog } from './load-binding.ts';\nimport type { GetOptions, PutOptions, Store, StoreContext, StoreGetOptions } from './store.ts';\nimport type { Transaction } from './transaction.ts';\nimport { type MaybePromise, when } from './util.ts';\n\nexport interface RocksDBOptions {\n\t/**\n\t * When `true`, RocksDB will do some enhancements for prefetching the data.\n\t * Defaults to `true`. Note that RocksDB defaults this to `false`.\n\t */\n\tadaptiveReadahead?: boolean;\n\n\t/**\n\t * When `true`, RocksDB will prefetch some data async and apply it if reads\n\t * are sequential and its internal automatic prefetching. Defaults to\n\t * `true`. Note that RocksDB defaults this to `false`.\n\t */\n\tasyncIO?: boolean;\n\n\t/**\n\t * When `true`, RocksDB will auto-tune the readahead size during scans\n\t * internally based on the block cache data when block caching is enabled,\n\t * an end key (e.g. upper bound) is set, and prefix is the same as the start\n\t * key. Defaults to `true`.\n\t */\n\tautoReadaheadSize?: boolean;\n\n\t/**\n\t * When `true`, after the iterator is closed, a background job is scheduled\n\t * to flush the job queue and delete obsolete files. Defaults to `true`.\n\t * Note that RocksDB defaults this to `false`.\n\t */\n\tbackgroundPurgeOnIteratorCleanup?: boolean;\n\n\t/**\n\t * When `true`, the iterator will fill the block cache. Filling the block\n\t * cache is not desirable for bulk scans and could impact eviction order.\n\t * Defaults to `false`. Note that RocksDB defaults this to `true`.\n\t */\n\tfillCache?: boolean;\n\n\t/**\n\t * The RocksDB readahead size. RocksDB does auto-readahead for iterators\n\t * when there is more than two reads for a table file. The readahead\n\t * starts at 8KB and doubles on every additional read up to 256KB. This\n\t * option can help if most of the range scans are large and if a larger\n\t * readahead than that enabled by auto-readahead is needed. Using a large\n\t * readahead size (> 2MB) can typically improve the performance of forward\n\t * iteration on spinning disks. Defaults to `0`.\n\t */\n\treadaheadSize?: number;\n\n\t/**\n\t * When `true`, creates a \"tailing iterator\" which is a special iterator\n\t * that has a view of the complete database including newly added data and\n\t * is optimized for sequential reads. This will return records that were\n\t * inserted into the database after the creation of the iterator. Defaults\n\t * to `false`.\n\t */\n\ttailing?: boolean;\n}\n\nexport interface CountEstimate {\n\t/**\n\t * The estimated number of keys.\n\t */\n\tcount: number;\n\n\t/**\n\t * Heuristic 0–1 indicator of how trustworthy `count` is; exactly 1 only\n\t * when the count is exact. Derived from the estimate's resolution\n\t * (SST data-block / memtable sampling granularity relative to the count),\n\t * the tombstone fraction of the overlapping SSTs, and — for open-ended\n\t * starts — the error compounded by complement subtraction. A heuristic\n\t * ordering signal, not a statistical bound.\n\t */\n\tconfidence: number;\n}\n\nexport interface RangeOptions extends RocksDBOptions {\n\t/**\n\t * The range end key, otherwise known as the \"upper bound\". Defaults to\n\t * the last key in the database.\n\t */\n\tend?: Key | Uint8Array;\n\n\t/**\n\t * When `true`, the iterator will exclude the first key if it matches the start key.\n\t * Defaults to `false`.\n\t */\n\texclusiveStart?: boolean;\n\n\t/**\n\t * When `true`, the iterator will include the last key if it matches the end\n\t * key. Defaults to `false`.\n\t */\n\tinclusiveEnd?: boolean;\n\n\t/**\n\t * The range start key, otherwise known as the \"lower bound\". Defaults to\n\t * the first key in the database.\n\t */\n\tstart?: Key | Uint8Array;\n}\n\nexport interface CountEstimateOptions extends RangeOptions {\n\t/**\n\t * Interpret `start` as the upper bound and `end` as the lower bound, as\n\t * `getRange()` does for reverse iteration. Defaults to `false`.\n\t */\n\treverse?: boolean;\n}\n\nexport interface IteratorOptions extends RangeOptions {\n\t// decoder?: (value: any) => any,\n\n\t// exactMatch?: boolean;\n\n\t/**\n\t * The maximum number of entries to yield. When set, iteration stops after\n\t * `limit` entries regardless of the range bounds. Values <= 0 yield nothing.\n\t * Unset means no limit.\n\t */\n\tlimit?: number;\n\n\t/**\n\t * A specific key to match which may result in zero, one, or many values.\n\t */\n\tkey?: Key;\n\n\t// offset?: number;\n\n\t/**\n\t * When `true`, only returns the number of values for the given query.\n\t */\n\tonlyCount?: boolean;\n\n\t/**\n\t * When `true`, the iterator will iterate in reverse order. Defaults to\n\t * `false`.\n\t */\n\treverse?: boolean;\n\n\t// snapshot?: boolean;\n\n\t/**\n\t * When `true`, decodes and returns the value. When `false`, the value is\n\t * omitted. Defaults to `true`.\n\t */\n\tvalues?: boolean;\n\n\t/**\n\t * When `true`, the iterator will only return the values.\n\t */\n\tvaluesOnly?: boolean;\n}\n\nexport interface DBITransactional {\n\ttransaction?: Transaction;\n}\n\n/**\n * The base class for all database operations. This base class is shared by\n * `RocksDatabase` and `Transaction`.\n *\n * This class is not meant to be used directly.\n */\nexport class DBI<T extends DBITransactional | unknown = unknown> {\n\t/**\n\t * The RocksDB context for `get()`, `put()`, and `remove()`.\n\t */\n\t_context: StoreContext;\n\n\t/**\n\t * The database store instance. The store instance is tied to the database\n\t * instance and shared with transaction instances.\n\t */\n\tstore: Store;\n\n\t/**\n\t * Initializes the DBI context.\n\t *\n\t * @param store - The store instance.\n\t * @param transaction - The transaction instance.\n\t */\n\tconstructor(store: Store, transaction?: NativeTransaction) {\n\t\tif (new.target === DBI) {\n\t\t\tthrow new Error('DBI is an abstract class and cannot be instantiated directly');\n\t\t}\n\n\t\t// this ideally should not be public, but JavaScript doesn't support\n\t\t// protected properties\n\t\tthis.store = store;\n\n\t\tthis._context = transaction || store.db;\n\t}\n\n\t/**\n\t * Adds a listener for the given key.\n\t *\n\t * @param event - The event name to add the listener for.\n\t * @param callback - The callback to add.\n\t */\n\taddListener(event: string, callback: (...args: any[]) => void): this {\n\t\tthis.store.db.addListener(event, callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Retrieves the value for the given key, then returns the decoded value.\n\t */\n\tget(key: Key, options?: GetOptions & T): MaybePromise<any | undefined> {\n\t\tif (this.store.decoderCopies) {\n\t\t\treturn when(\n\t\t\t\t() => this.getBinaryFast(key, options),\n\t\t\t\t(result) => {\n\t\t\t\t\tif (result === undefined || result === FRESH_VERSION_FLAG) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (options?.skipDecode) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn this.store.decodeValue(result as BufferWithDataView);\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn when(\n\t\t\t() => this.getBinary(key, options),\n\t\t\t(result) =>\n\t\t\t\tresult === undefined || result === FRESH_VERSION_FLAG\n\t\t\t\t\t? result\n\t\t\t\t\t: this.store.encoding === 'binary' || !this.store.decoder || options?.skipDecode\n\t\t\t\t\t\t? result\n\t\t\t\t\t\t: this.store.decodeValue(result as BufferWithDataView)\n\t\t);\n\t}\n\n\t/**\n\t * Retrieves the binary data for the given key. This is just like `get()`,\n\t * but bypasses the decoder.\n\t *\n\t * Note: Used by HDBreplication.\n\t */\n\tgetBinary(key: Key, options?: GetOptions & T): MaybePromise<Buffer | number | undefined> {\n\t\tif (!this.store.isOpen()) {\n\t\t\treturn Promise.reject(new Error('Database not open'));\n\t\t}\n\n\t\treturn this.store.get(this._context, key, true, options as StoreGetOptions);\n\t}\n\n\t/**\n\t * Synchronously retrieves the binary data for the given key.\n\t */\n\tgetBinarySync(key: Key, options?: GetOptions & T): Buffer | number | undefined {\n\t\tif (!this.store.isOpen()) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\treturn this.store.getSync(this._context, key, true, options);\n\t}\n\n\t/**\n\t * Retrieves the binary data for the given key using a preallocated,\n\t * reusable buffer. Data in the buffer is only valid until the next get\n\t * operation (including cursor operations).\n\t *\n\t * Note: The reusable buffer slightly differs from a typical buffer:\n\t * - `.length` is set to the size of the value\n\t * - `.byteLength` is set to the size of the full allocated memory area for\n\t * the buffer (usually much larger).\n\t */\n\tgetBinaryFast(key: Key, options?: GetOptions & T): MaybePromise<Buffer | number | undefined> {\n\t\tif (!this.store.isOpen()) {\n\t\t\treturn Promise.reject(new Error('Database not open'));\n\t\t}\n\n\t\treturn this.store.get(this._context, key, false, options as StoreGetOptions);\n\t}\n\n\t/**\n\t * Synchronously retrieves the binary data for the given key using a\n\t * preallocated, reusable buffer. Data in the buffer is only valid until the\n\t * next get operation (including cursor operations).\n\t */\n\tgetBinaryFastSync(key: Key, options?: GetOptions & T): Buffer | number | undefined {\n\t\tif (!this.store.isOpen()) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\treturn this.store.getSync(this._context, key, false, options);\n\t}\n\n\t/**\n\t * Retrieves all keys within a range.\n\t */\n\tgetKeys(options?: IteratorOptions & T): any | undefined {\n\t\treturn this.store.getKeys(this._context, options);\n\t}\n\n\t/**\n\t * Retrieves the number of keys within a range.\n\t *\n\t * @param options - The range options.\n\t * @returns The number of keys within the range.\n\t *\n\t * @example\n\t * ```typescript\n\t * const total = db.getKeysCount();\n\t * const range = db.getKeysCount({ start: 'a', end: 'z' });\n\t * ```\n\t */\n\tgetKeysCount(options?: RangeOptions & T): number {\n\t\treturn this.store.getKeysCount(this._context, options);\n\t}\n\n\t/**\n\t * Retrieves a range of keys and their values.\n\t *\n\t * @param options - The iterator options.\n\t * @returns A range iterable.\n\t *\n\t * @example\n\t * ```typescript\n\t * for (const { key, value } of db.getRange()) {\n\t * console.log({ key, value });\n\t * }\n\t *\n\t * for (const { key, value } of db.getRange({ start: 'a', end: 'z' })) {\n\t * console.log({ key, value });\n\t * }\n\t * ```\n\t */\n\tgetRange(options?: IteratorOptions & T): any | undefined {\n\t\treturn this.store.getRange(this._context, options);\n\t}\n\n\t/**\n\t * Synchronously retrieves the value for the given key, then returns the\n\t * decoded value.\n\t */\n\tgetSync(key: Key, options?: GetOptions & T): any | undefined {\n\t\tif (this.store.decoderCopies) {\n\t\t\tconst bytes = this.getBinaryFastSync(key, options);\n\t\t\treturn bytes === undefined || bytes === FRESH_VERSION_FLAG\n\t\t\t\t? bytes\n\t\t\t\t: this.store.decodeValue(bytes as BufferWithDataView);\n\t\t}\n\n\t\tif (this.store.encoding === 'binary') {\n\t\t\treturn this.getBinarySync(key, options);\n\t\t}\n\n\t\tif (this.store.decoder) {\n\t\t\tconst result = this.getBinarySync(key, options);\n\t\t\treturn !result || result === FRESH_VERSION_FLAG\n\t\t\t\t? result\n\t\t\t\t: this.store.decodeValue(result as BufferWithDataView);\n\t\t}\n\n\t\tif (!this.store.isOpen()) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\treturn this.store.decodeValue(this.store.getSync(this._context, key, true, options));\n\t}\n\n\t/**\n\t * Gets the number of listeners for the given key.\n\t *\n\t * @param event - The event name to get the listeners for.\n\t * @returns The number of listeners for the given key.\n\t */\n\tlisteners(event: string | BufferWithDataView): number {\n\t\treturn this.store.db.listeners(event);\n\t}\n\n\t/**\n\t * Notifies an event for the given key.\n\t *\n\t * @param event - The event name to emit the event for.\n\t * @param args - The arguments to emit.\n\t * @returns `true` if there were listeners, `false` otherwise.\n\t */\n\tnotify(event: string, ...args: any[]): boolean {\n\t\treturn this.store.db.notify(event, args);\n\t}\n\n\t/**\n\t * Alias for `removeListener()`.\n\t *\n\t * @param event - The event name to remove the listener for.\n\t * @param callback - The callback to remove.\n\t */\n\toff(event: string, callback: (...args: any[]) => void): this {\n\t\tthis.store.db.removeListener(event, callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Alias for `addListener()`.\n\t *\n\t * @param event - The event name to add the listener for.\n\t * @param callback - The callback to add.\n\t */\n\ton(event: string, callback: (...args: any[]) => void): this {\n\t\tthis.store.db.addListener(event, callback);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Adds a one-time listener, then automatically removes it.\n\t *\n\t * @param event - The event name to add the listener for.\n\t * @param callback - The callback to add.\n\t */\n\tonce(event: string, callback: (...args: any[]) => void): this {\n\t\tconst wrapper = (...args: any[]) => {\n\t\t\tthis.removeListener(event, wrapper);\n\t\t\tcallback(...args);\n\t\t};\n\t\tthis.store.db.addListener(event, wrapper);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stores a value for the given key.\n\t *\n\t * @param key - The key to store the value for.\n\t * @param value - The value to store.\n\t * @param options - The put options.\n\t * @returns The key and value.\n\t *\n\t * @example\n\t * ```typescript\n\t * await db.put('a', 'b');\n\t * ```\n\t */\n\tasync put(key: Key, value: any, options?: PutOptions & T): Promise<void> {\n\t\treturn this.store.putSync(this._context, key, value, options);\n\t}\n\n\t/**\n\t * Synchronously stores a value for the given key.\n\t *\n\t * @param key - The key to store the value for.\n\t * @param value - The value to store.\n\t * @param options - The put options.\n\t * @returns The key and value.\n\t *\n\t * @example\n\t * ```typescript\n\t * db.putSync('a', 'b');\n\t * ```\n\t */\n\tputSync(key: Key, value: any, options?: PutOptions & T): void {\n\t\treturn this.store.putSync(this._context, key, value, options);\n\t}\n\n\t/**\n\t * Removes a value for the given key. If the key does not exist, it will\n\t * not error.\n\t *\n\t * @param key - The key to remove the value for.\n\t * @param options - The remove options.\n\t * @returns The key and value.\n\t *\n\t * @example\n\t * ```typescript\n\t * await db.remove('a');\n\t * ```\n\t */\n\tasync remove(key: Key, options?: T): Promise<void> {\n\t\treturn this.store.removeSync(this._context, key, options);\n\t}\n\n\t/**\n\t * Removes a value for the given key. If the key does not exist, it will\n\t * not error.\n\t *\n\t * @param key - The key to remove the value for.\n\t * @param options - The remove options.\n\t * @returns The key and value.\n\t *\n\t * @example\n\t * ```typescript\n\t * db.removeSync('a');\n\t * ```\n\t */\n\tremoveSync(key: Key, options?: T): void {\n\t\treturn this.store.removeSync(this._context, key, options);\n\t}\n\n\t/**\n\t * Removes an event listener. You must specify the exact same callback that was\n\t * used in `addListener()`.\n\t *\n\t * @param event - The event name to remove the listener for.\n\t * @param callback - The callback to remove.\n\t */\n\tremoveListener(event: string, callback: (value?: any) => void): boolean {\n\t\treturn this.store.db.removeListener(event, callback);\n\t}\n\n\t/**\n\t * Get or create a transaction log instance.\n\t *\n\t * @param name - The name of the transaction log.\n\t * @returns The transaction log.\n\t */\n\tuseLog(name: string | number): TransactionLog {\n\t\treturn this.store.useLog(this._context, name);\n\t}\n}\n","/**\n * A minimal, dependency-free streaming USTAR (POSIX tar) encoder.\n *\n * Built for streaming whole-database backups: the set of live RocksDB files\n * (SSTs, blobs, MANIFEST, CURRENT, OPTIONS, WAL) is serialized into a single\n * tar byte stream that can be piped to any destination and unpacked with\n * standard tools (`tar -xf`). The encoder never buffers a whole file — each\n * entry's payload is streamed through in chunks — so peak memory stays flat\n * regardless of database size.\n *\n * Backpressure is the caller's lever: every method `await`s the {@link TarSink},\n * so wiring the sink to a stream writer's `write()` naturally paces production\n * to the consumer.\n *\n * Only what a RocksDB backup needs is implemented: regular files. Paths longer\n * than USTAR's 100-byte `name` field are split across the `name` and `prefix`\n * fields (~255 bytes total), which covers `transaction_logs/<store>/<file>`\n * entries; GNU/pax long-name extensions are not implemented, so a path that\n * still doesn't fit throws rather than being silently truncated. File sizes\n * larger than the octal `size` field can hold (~8 GiB) fall back to the GNU\n * base-256 encoding.\n */\n\n/** Size of a tar block. Every header and the archive length are multiples of this. */\nconst BLOCK_SIZE = 512;\n\n/** Maximum bytes for the USTAR `name` field. */\nconst MAX_NAME_LENGTH = 100;\n\n/** Maximum bytes for the USTAR `prefix` field (holds the leading directories). */\nconst MAX_PREFIX_LENGTH = 155;\n\nconst textEncoder = new TextEncoder();\nconst textDecoder = new TextDecoder();\n\n/**\n * Destination for encoded bytes. Returning a promise applies backpressure: the\n * encoder will not produce the next chunk until it resolves. Chunks must be\n * consumed (or copied) before the returned promise resolves, since the encoder\n * may reuse or hand back borrowed buffers afterward.\n */\nexport type TarSink = (chunk: Uint8Array) => void | Promise<void>;\n\n/**\n * Per-entry tar metadata. All fields are cosmetic for backup/restore (RocksDB\n * does not consult them); they exist so the archive is well-formed for external\n * tools.\n */\nexport type TarEntryOptions = {\n\t/** Unix file mode, masked to 12 bits. Default `0o644`. */\n\tmode?: number;\n\t/**\n\t * Modification time in seconds since the epoch. Default `0` so archives are\n\t * reproducible (byte-identical for identical inputs).\n\t */\n\tmtime?: number;\n};\n\n/**\n * Writes a UTF-8 string into a fixed-width header field, left-justified and\n * NUL-padded (the block is already zero-filled, so nothing else is needed).\n * Throws if the encoded value does not fit — tar fields are silently lossy\n * otherwise, which corrupts the archive.\n */\nfunction writeField(block: Uint8Array, value: string, offset: number, length: number): void {\n\tconst bytes = textEncoder.encode(value);\n\tif (bytes.length > length) {\n\t\tthrow new RangeError(`tar field value ${JSON.stringify(value)} exceeds ${length} bytes`);\n\t}\n\tblock.set(bytes, offset);\n}\n\n/**\n * Writes a non-negative integer as a NUL-terminated, zero-padded octal string\n * into a `length`-byte field (so `length - 1` octal digits). Values too large\n * for octal fall back to the GNU base-256 extension, where the high bit of the\n * first byte is set and the magnitude is stored big-endian in the remainder.\n */\nfunction writeOctal(block: Uint8Array, value: number, offset: number, length: number): void {\n\tconst digits = length - 1;\n\tif (value > 8 ** digits - 1) {\n\t\t// GNU base-256: signal byte 0x80, then big-endian magnitude. JS safe\n\t\t// integers are 53 bits, well within the (length - 1) * 8 bits available.\n\t\tlet v = value;\n\t\tfor (let i = offset + length - 1; i > offset; i--) {\n\t\t\tblock[i] = v & 0xff;\n\t\t\tv = Math.floor(v / 256);\n\t\t}\n\t\tblock[offset] = 0x80;\n\t\treturn;\n\t}\n\tconst str = value.toString(8).padStart(digits, '0');\n\tfor (let i = 0; i < digits; i++) {\n\t\tblock[offset + i] = str.charCodeAt(i);\n\t}\n\t// block[offset + digits] stays 0 (NUL terminator).\n}\n\n/**\n * Computes and writes the USTAR header checksum: the unsigned sum of all 512\n * header bytes with the checksum field itself taken as ASCII spaces. Stored as\n * six octal digits, a NUL, then a space (the conventional encoding).\n */\nfunction writeChecksum(block: Uint8Array): void {\n\tfor (let i = 148; i < 156; i++) {\n\t\tblock[i] = 0x20; // spaces during computation\n\t}\n\tlet sum = 0;\n\tfor (let i = 0; i < BLOCK_SIZE; i++) {\n\t\tsum += block[i];\n\t}\n\tconst str = sum.toString(8).padStart(6, '0');\n\tfor (let i = 0; i < 6; i++) {\n\t\tblock[148 + i] = str.charCodeAt(i);\n\t}\n\tblock[154] = 0; // NUL\n\tblock[155] = 0x20; // space\n}\n\n/**\n * Splits a path into USTAR `name` (<=100 bytes) and `prefix` (<=155 bytes)\n * fields at a `/` boundary; a reader rejoins them as `prefix + \"/\" + name`.\n * Returns an empty prefix when the whole path fits in `name`. Throws when the\n * path cannot be represented — a trailing component over 100 bytes, or leading\n * directories that don't fit in 155. RocksDB and transaction-log filenames never\n * hit this; only a pathological log-store name would.\n */\nfunction splitTarName(path: string): { name: string; prefix: string } {\n\t// Encode once and search the bytes: `/` is ASCII and UTF-8 never embeds an\n\t// ASCII byte inside a multi-byte sequence, so every 0x2f byte is a real\n\t// separator and both halves of a split there are valid UTF-8.\n\tconst encoded = textEncoder.encode(path);\n\tif (encoded.length <= MAX_NAME_LENGTH) {\n\t\treturn { name: path, prefix: '' };\n\t}\n\tlet best = -1;\n\tfor (let i = 0; i < encoded.length; i++) {\n\t\tif (encoded[i] !== 0x2f) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst prefixLength = i;\n\t\tconst nameLength = encoded.length - i - 1;\n\t\tif (nameLength > 0 && nameLength <= MAX_NAME_LENGTH && prefixLength <= MAX_PREFIX_LENGTH) {\n\t\t\t// As the split moves right the prefix grows and the name shrinks, so the\n\t\t\t// last split satisfying both bounds packs the most into `prefix`.\n\t\t\tbest = i;\n\t\t}\n\t}\n\tif (best === -1) {\n\t\tthrow new RangeError(\n\t\t\t`tar entry name ${JSON.stringify(path)} does not fit the USTAR name (<=${MAX_NAME_LENGTH}) + prefix (<=${MAX_PREFIX_LENGTH}) fields`\n\t\t);\n\t}\n\treturn {\n\t\tname: textDecoder.decode(encoded.subarray(best + 1)),\n\t\tprefix: textDecoder.decode(encoded.subarray(0, best)),\n\t};\n}\n\n/**\n * Builds a single 512-byte USTAR header block for a regular file. Long paths are\n * split across the `name` and `prefix` fields (see {@link splitTarName}).\n */\nfunction buildHeader(name: string, size: number, mode: number, mtime: number): Uint8Array {\n\tconst block = new Uint8Array(BLOCK_SIZE);\n\tconst split = splitTarName(name);\n\twriteField(block, split.name, 0, MAX_NAME_LENGTH);\n\twriteOctal(block, mode & 0o7777, 100, 8); // mode\n\twriteOctal(block, 0, 108, 8); // uid\n\twriteOctal(block, 0, 116, 8); // gid\n\twriteOctal(block, size, 124, 12); // size\n\twriteOctal(block, Math.floor(mtime), 136, 12); // mtime (floored — octal field, no fraction)\n\tblock[156] = 0x30; // typeflag '0' = regular file\n\twriteField(block, 'ustar', 257, 6); // magic \"ustar\\0\"\n\tblock[263] = 0x30; // version \"00\"\n\tblock[264] = 0x30;\n\tif (split.prefix.length > 0) {\n\t\twriteField(block, split.prefix, 345, MAX_PREFIX_LENGTH); // prefix\n\t}\n\twriteChecksum(block);\n\treturn block;\n}\n\n/**\n * Streaming USTAR encoder. Usage is a strict sequence per file —\n * {@link TarEncoder.addFile} once, then {@link TarEncoder.writeData} until the\n * declared size is reached — followed by a single {@link TarEncoder.finalize}:\n *\n * ```ts\n * const tar = new TarEncoder((chunk) => writer.write(chunk));\n * await tar.addFile('CURRENT', current.length);\n * await tar.writeData(current);\n * await tar.addFile('000123.sst', sstSize);\n * for await (const chunk of sstChunks) await tar.writeData(chunk);\n * await tar.finalize();\n * ```\n *\n * The size passed to `addFile` is authoritative: tar records it in the header\n * before any payload, so it must be known up front (it is — RocksDB's\n * `GetLiveFilesStorageInfo` returns each file's exact size). Writing more or\n * fewer bytes than declared throws.\n */\nexport class TarEncoder {\n\t#sink: TarSink;\n\t/** Payload bytes still expected for the current entry. */\n\t#remaining: number = 0;\n\t/** Zero-padding bytes owed after the current entry's payload reaches a block boundary. */\n\t#pad: number = 0;\n\t#finalized: boolean = false;\n\n\tconstructor(sink: TarSink) {\n\t\tthis.#sink = sink;\n\t}\n\n\t/**\n\t * Emits the header for a new file entry. Must be preceded by completing any\n\t * prior entry's payload. After this, exactly `size` bytes must be supplied\n\t * via {@link TarEncoder.writeData} before the next `addFile` or `finalize`.\n\t */\n\tasync addFile(name: string, size: number, options?: TarEntryOptions): Promise<void> {\n\t\tif (this.#finalized) {\n\t\t\tthrow new Error('TarEncoder already finalized');\n\t\t}\n\t\tif (this.#remaining !== 0) {\n\t\t\tthrow new Error(`previous tar entry incomplete: ${this.#remaining} byte(s) unwritten`);\n\t\t}\n\t\tif (!Number.isInteger(size) || size < 0) {\n\t\t\tthrow new RangeError('tar entry size must be a non-negative integer');\n\t\t}\n\t\t// Build the header first so an invalid/unsplittable name throws before any\n\t\t// encoder state is mutated.\n\t\tconst header = buildHeader(name, size, options?.mode ?? 0o644, options?.mtime ?? 0);\n\t\tthis.#remaining = size;\n\t\tthis.#pad = (BLOCK_SIZE - (size % BLOCK_SIZE)) % BLOCK_SIZE;\n\t\tawait this.#sink(header);\n\t}\n\n\t/**\n\t * Streams a chunk of the current entry's payload. Chunks may be any size; the\n\t * total across all `writeData` calls for an entry must equal the size passed\n\t * to {@link TarEncoder.addFile}. Block padding is emitted automatically once\n\t * the final byte of an entry is written.\n\t */\n\tasync writeData(chunk: Uint8Array): Promise<void> {\n\t\tif (this.#finalized) {\n\t\t\tthrow new Error('TarEncoder already finalized');\n\t\t}\n\t\tif (chunk.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tif (chunk.length > this.#remaining) {\n\t\t\tthrow new RangeError(\n\t\t\t\t`tar data overruns entry size by ${chunk.length - this.#remaining} byte(s)`\n\t\t\t);\n\t\t}\n\t\tthis.#remaining -= chunk.length;\n\t\tawait this.#sink(chunk);\n\t\tif (this.#remaining === 0 && this.#pad > 0) {\n\t\t\tconst pad = this.#pad;\n\t\t\tthis.#pad = 0;\n\t\t\tawait this.#sink(new Uint8Array(pad));\n\t\t}\n\t}\n\n\t/**\n\t * Convenience for an entry whose contents are already fully in memory (e.g.\n\t * the small `CURRENT`/`OPTIONS` files RocksDB returns inline).\n\t */\n\tasync addFileData(name: string, data: Uint8Array, options?: TarEntryOptions): Promise<void> {\n\t\tawait this.addFile(name, data.length, options);\n\t\tawait this.writeData(data);\n\t}\n\n\t/**\n\t * Writes the two zero-filled blocks that mark end-of-archive. The encoder is\n\t * unusable afterward. Throws if the current entry is not fully written, so a\n\t * truncated stream cannot be silently finalized into a valid-looking archive.\n\t */\n\tasync finalize(): Promise<void> {\n\t\tif (this.#finalized) {\n\t\t\tthrow new Error('TarEncoder already finalized');\n\t\t}\n\t\tif (this.#remaining !== 0) {\n\t\t\tthrow new Error(\n\t\t\t\t`cannot finalize: current tar entry has ${this.#remaining} byte(s) unwritten`\n\t\t\t);\n\t\t}\n\t\tthis.#finalized = true;\n\t\tawait this.#sink(new Uint8Array(BLOCK_SIZE * 2));\n\t}\n}\n","import type { NativeDatabase } from './load-binding.ts';\nimport { TarEncoder } from './tar.ts';\n\n/**\n * Options for streaming a backup via `db.backup(stream)`.\n */\nexport interface BackupStreamOptions {\n\t/**\n\t * Flush the memtable before streaming. Defaults to `true` when the database\n\t * was opened with `disableWAL` (otherwise unflushed data would be missing\n\t * from the stream), and `false` otherwise — matching `db.backup(dir)`.\n\t */\n\tflushBeforeBackup?: boolean;\n\n\t/**\n\t * Gzip-compress the archive before writing it to the stream, producing a\n\t * `.tar.gz` stream instead of a plain `.tar`. Defaults to `false`.\n\t *\n\t * Compression runs in the runtime's `CompressionStream`, downstream of the tar\n\t * encoder, so end-to-end backpressure is preserved. RocksDB SST files are\n\t * usually already block-compressed, so the additional savings vary with the\n\t * data and the configured compression.\n\t */\n\tgzip?: boolean;\n\n\t/**\n\t * Also stream the transaction log store as `transaction_logs/<store>/…`\n\t * entries (each `*.txnlog` and `txn.state` file) after the database files.\n\t * Defaults to `false`. Extraction reconstructs them next to the database, and\n\t * their mtimes are preserved so the store's age-based rotation/retention stays\n\t * correct.\n\t */\n\ttransactionLogs?: boolean;\n}\n\n/** Native event discriminator: a new file header (vs. a payload chunk). */\nconst EVENT_FILE = 0;\n\n/**\n * Streams a consistent snapshot of the database to a `WritableStream` as a tar\n * archive, with no intermediate copy on disk. The set of live RocksDB files is\n * enumerated and read natively; each file header and payload chunk is framed\n * into the {@link TarEncoder} here in JS and written to `stream`.\n *\n * Backpressure flows end to end: the encoder awaits each `writer.write()`, and\n * the native producer awaits each `emit()` before reading the next chunk, so a\n * slow consumer paces the entire pipeline rather than buffering in memory.\n *\n * The resulting archive can be unpacked with any tar tool (`tar -xf`) into a\n * directory that opens directly as a RocksDB database.\n */\nexport async function backupToStream(\n\tdb: NativeDatabase,\n\tstream: WritableStream<Uint8Array>,\n\toptions?: BackupStreamOptions\n): Promise<void> {\n\t// With `gzip`, the tar bytes are written into a CompressionStream whose\n\t// compressed output is piped to the caller's stream. `pipeTo` propagates\n\t// backpressure and, on failure, aborts the destination — so the end-to-end\n\t// pacing and error handling carry through the compressor unchanged.\n\tlet tarDestination: WritableStream<Uint8Array>;\n\tlet piped: Promise<void> | undefined;\n\tif (options?.gzip) {\n\t\tconst gzip = new CompressionStream('gzip');\n\t\tpiped = gzip.readable.pipeTo(stream);\n\t\ttarDestination = gzip.writable as WritableStream<Uint8Array>;\n\t} else {\n\t\ttarDestination = stream;\n\t}\n\n\tconst writer = tarDestination.getWriter();\n\tconst tar = new TarEncoder((chunk) => writer.write(chunk));\n\n\t// Native invokes `emit` once per file header and once per payload chunk, and\n\t// awaits the returned promise before producing the next event. A rejection\n\t// here (e.g. the consumer errored) aborts the native stream.\n\tconst emit = async (\n\t\tkind: number,\n\t\tdata: string | Uint8Array,\n\t\tsize: number,\n\t\tmtime: number\n\t): Promise<void> => {\n\t\tif (kind === EVENT_FILE) {\n\t\t\tawait tar.addFile(data as string, size, { mtime });\n\t\t} else {\n\t\t\tawait tar.writeData(data as Uint8Array);\n\t\t}\n\t};\n\n\ttry {\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tdb.backupStream(resolve, reject, emit, options);\n\t\t});\n\t\tawait tar.finalize();\n\t\tawait writer.close();\n\t\t// Closing the tar destination flushes and closes the compressor, which\n\t\t// closes its readable end and lets the pipe finish writing to the caller.\n\t\tif (piped) {\n\t\t\tawait piped;\n\t\t}\n\t} catch (err) {\n\t\t// Surface the failure to the consumer and release the writer lock. The\n\t\t// writer may already be errored (consumer-side failure), so ignore abort\n\t\t// rejections and rethrow the original cause.\n\t\tawait writer.abort(err).catch(() => {});\n\t\t// Aborting the compressor rejects the pipe; settle it so the rejection is\n\t\t// observed rather than surfacing as an unhandled rejection.\n\t\tif (piped) {\n\t\t\tawait piped.catch(() => {});\n\t\t}\n\t\tthrow err;\n\t}\n}\n","import type { BufferWithDataView, Key } from './encoding.ts';\nimport { constants, type NativeIteratorCls, type NativeIteratorResult } from './load-binding.ts';\nimport { ITERATOR_STATE, KEY_BUFFER, type Store, VALUE_BUFFER } from './store.ts';\n\nconst { ITERATOR_RESULT_DONE, ITERATOR_RESULT_FAST } = constants;\n\nexport interface DBIteratorValue<T> {\n\tkey: Key;\n\tvalue: T;\n}\n\nconst DONE_RESULT: IteratorResult<DBIteratorValue<unknown>> = Object.freeze({\n\tdone: true,\n\tvalue: undefined as unknown,\n}) as IteratorResult<DBIteratorValue<unknown>>;\n\n/**\n * Wraps the `NativeIterator` C++ binding, decoding keys and values from the\n * shared key/value buffers (fast path) or from per-iteration buffers (slow\n * fallback path used for oversized data or stable-buffer decoders).\n *\n * The native `next()` returns a primitive signal (and writes lengths to the\n * shared `ITERATOR_STATE` buffer) instead of constructing a JS result object,\n * so this class is responsible for building the `IteratorResult`.\n */\nexport class DBIterator<T> implements Iterator<DBIteratorValue<T>> {\n\titerator: InstanceType<typeof NativeIteratorCls>;\n\tstore: Store;\n\t#includeValues: boolean;\n\t// When set, iteration stops after this many entries. The native iterator has no\n\t// notion of a count bound, so the limit is enforced here in the JS layer.\n\t#limit: number | undefined;\n\t#yielded = 0;\n\n\tconstructor(\n\t\titerator: InstanceType<typeof NativeIteratorCls>,\n\t\tstore: Store,\n\t\tincludeValues: boolean,\n\t\tlimit?: number\n\t) {\n\t\tthis.iterator = iterator;\n\t\tthis.store = store;\n\t\tthis.#includeValues = includeValues;\n\t\t// Normalize a nullish limit to `undefined` (no limit). A caller passing `null` must not be\n\t\t// read as a 0 limit by the `#yielded >= this.#limit` check below (null coerces to 0).\n\t\tthis.#limit = limit ?? undefined;\n\t}\n\n\t[Symbol.iterator](): Iterator<DBIteratorValue<T>> {\n\t\treturn this;\n\t}\n\n\tnext(): IteratorResult<DBIteratorValue<T>> {\n\t\tif (this.#limit !== undefined && this.#yielded >= this.#limit) {\n\t\t\t// Reached the requested limit: release the native iterator and stop.\n\t\t\tthis.iterator.return?.();\n\t\t\treturn DONE_RESULT as IteratorResult<DBIteratorValue<T>>;\n\t\t}\n\n\t\tconst result: NativeIteratorResult = this.iterator.next();\n\n\t\tif (result === ITERATOR_RESULT_DONE) {\n\t\t\treturn DONE_RESULT as IteratorResult<DBIteratorValue<T>>;\n\t\t}\n\n\t\tthis.#yielded++;\n\t\tconst includeValues = this.#includeValues;\n\t\tconst value: Partial<DBIteratorValue<T>> = {};\n\n\t\tif (result === ITERATOR_RESULT_FAST) {\n\t\t\t// Fast path: key bytes are in the shared KEY_BUFFER, value bytes\n\t\t\t// are in the shared VALUE_BUFFER, and lengths are in ITERATOR_STATE.\n\t\t\tvalue.key = this.store.readKey(KEY_BUFFER, 0, ITERATOR_STATE[0]);\n\t\t\tif (includeValues) {\n\t\t\t\tVALUE_BUFFER.end = ITERATOR_STATE[1];\n\t\t\t\tvalue.value = this.store.decodeValue(VALUE_BUFFER) as T;\n\t\t\t}\n\t\t} else {\n\t\t\t// Slow path: data didn't fit in shared buffers (or decoder needs\n\t\t\t// stable buffer). The native side allocated fresh buffers for us.\n\t\t\tconst slow = result as { key: Buffer; value?: Buffer };\n\t\t\tvalue.key = this.store.decodeKey(slow.key);\n\t\t\tif (includeValues && slow.value !== undefined) {\n\t\t\t\tvalue.value = this.store.decodeValue(slow.value as BufferWithDataView) as T;\n\t\t\t}\n\t\t}\n\n\t\treturn { done: false, value: value as DBIteratorValue<T> };\n\t}\n\n\treturn(value?: any): IteratorResult<DBIteratorValue<T>, any> {\n\t\tthis.iterator.return?.();\n\t\treturn { done: true, value };\n\t}\n\n\tthrow(err: unknown): IteratorResult<DBIteratorValue<T>, any> {\n\t\tthis.iterator.throw?.(err);\n\t\tthrow err;\n\t}\n}\n","import * as orderedBinary from 'ordered-binary';\n\nexport type Key = Key[] | string | symbol | number | boolean | Uint8Array | Buffer | null;\n\nexport interface BufferWithDataView extends Buffer {\n\tdataView: DataView;\n\tstart: number;\n\tend: number;\n}\n\nexport type EncoderFunction = new (options?: any) => Encoder;\n\nexport interface Encoder {\n\tcopyBuffers?: boolean;\n\tdecode?: (buffer: BufferWithDataView, options?: { end: number }) => any;\n\tencode?: (value: any, mode?: number) => Buffer; // | string;\n\tEncoder?: EncoderFunction;\n\tfreezeData?: boolean;\n\tname?: string;\n\tneedsStableBuffer?: boolean;\n\trandomAccessStructure?: boolean;\n\treadKey?: (buffer: Buffer, start: number, end: number, inSequence?: boolean) => any;\n\tstructuredClone?: boolean;\n\tstructures?: any[];\n\tuseFloat32?: boolean;\n\twriteKey?: (key: any, target: Buffer, position: number, inSequence?: boolean) => number;\n}\n\nexport type Encoding = 'binary' | 'ordered-binary' | 'msgpack' | false;\n\nexport interface KeyEncoder {\n\treadKey?: ReadKeyFunction<Key>;\n\twriteKey?: WriteKeyFunction;\n}\n\nexport type KeyEncoding = 'binary' | 'ordered-binary' | 'uint32';\n\nexport type ReadKeyFunction<T> = (source: BufferWithDataView, start: number, end?: number) => T;\nexport type WriteKeyFunction = (key: Key, target: BufferWithDataView, start: number) => number;\n\n/**\n * Initializes the key encoder functions.\n *\n * @param keyEncoding - The key encoding to use.\n * @param keyEncoder - The key encoder to use.\n * @returns The key encoder.\n */\nexport function initKeyEncoder(\n\trequestedKeyEncoding?: KeyEncoding | undefined,\n\tkeyEncoder?: KeyEncoder | undefined\n): { keyEncoding: KeyEncoding; readKey: ReadKeyFunction<Key>; writeKey: WriteKeyFunction } {\n\tconst keyEncoding: KeyEncoding = requestedKeyEncoding ?? 'ordered-binary';\n\n\tif (keyEncoder) {\n\t\tconst { readKey, writeKey } = keyEncoder;\n\t\tif (!readKey || !writeKey) {\n\t\t\tthrow new Error('Custom key encoder must provide both readKey and writeKey');\n\t\t}\n\t\treturn { keyEncoding, readKey, writeKey };\n\t}\n\n\tif (keyEncoding === 'binary') {\n\t\treturn {\n\t\t\tkeyEncoding,\n\t\t\treadKey(source: BufferWithDataView, start: number, end?: number): Uint8Array {\n\t\t\t\treturn Uint8Array.prototype.slice.call(source, start, end);\n\t\t\t},\n\t\t\twriteKey(key: Key, target: BufferWithDataView, start: number): number {\n\t\t\t\tconst keyBuffer = key instanceof Buffer ? key : Buffer.from(String(key));\n\t\t\t\ttarget.set(keyBuffer, start);\n\t\t\t\treturn keyBuffer.length + start;\n\t\t\t},\n\t\t};\n\t}\n\n\tif (keyEncoding === 'uint32') {\n\t\treturn {\n\t\t\tkeyEncoding,\n\t\t\treadKey(source: BufferWithDataView, start: number, _end?: number): number {\n\t\t\t\tif (!source.dataView) {\n\t\t\t\t\tsource.dataView = new DataView(source.buffer);\n\t\t\t\t}\n\t\t\t\treturn source.dataView.getUint32(start, true);\n\t\t\t},\n\t\t\twriteKey(key: Key, target: BufferWithDataView, start: number): number {\n\t\t\t\tconst keyNumber = Number(key);\n\t\t\t\tif (isNaN(keyNumber)) {\n\t\t\t\t\tthrow new TypeError('Key is not a number');\n\t\t\t\t}\n\t\t\t\ttarget.dataView.setUint32(start, keyNumber, true);\n\t\t\t\treturn start + 4;\n\t\t\t},\n\t\t};\n\t}\n\n\tif (keyEncoding === 'ordered-binary') {\n\t\treturn {\n\t\t\tkeyEncoding,\n\t\t\treadKey: orderedBinary.readKey,\n\t\t\twriteKey: orderedBinary.writeKey as WriteKeyFunction,\n\t\t};\n\t}\n\n\tthrow new Error(`Invalid key encoding: ${keyEncoding}`);\n}\n\n/**\n * Creates a fixed-size buffer with a data view, start, and end properties.\n *\n * Note: It uses `Buffer.allocUnsafe()` because it's the fastest by using\n * Node.js's preallocated memory pool, though the memory is not zeroed out.\n *\n * @param size - The size of the buffer.\n * @returns The buffer with a data view.\n */\nexport function createFixedBuffer(size: number): BufferWithDataView {\n\tconst buffer = Buffer.allocUnsafeSlow(size) as BufferWithDataView;\n\tbuffer.dataView = new DataView(buffer.buffer);\n\tbuffer.start = 0;\n\tbuffer.end = 0;\n\treturn buffer;\n}\n","import { type BackupStreamOptions, backupToStream } from './backup-stream.ts';\nimport { assertBackupDirOutsideDatabase, type BackupOptions } from './backup.ts';\nimport { DBIterator, type DBIteratorValue } from './dbi-iterator.ts';\nimport type {\n\tCountEstimate,\n\tCountEstimateOptions,\n\tDBITransactional,\n\tIteratorOptions,\n\tRangeOptions,\n} from './dbi.ts';\nimport {\n\ttype BufferWithDataView,\n\tcreateFixedBuffer,\n\ttype Encoder,\n\ttype Encoding,\n\tinitKeyEncoder,\n\ttype Key,\n\ttype KeyEncoding,\n\ttype ReadKeyFunction,\n\ttype WriteKeyFunction,\n} from './encoding.ts';\nimport {\n\tconstants,\n\tNativeDatabase,\n\ttype NativeDatabaseOptions,\n\tNativeIterator,\n\tNativeTransaction,\n\tstats,\n\tsupportedCompression,\n\ttype TransactionLog,\n\ttype UserSharedBufferCallback,\n} from './load-binding.ts';\nimport { parseDuration } from './util.ts';\nimport { ExtendedIterable } from '@harperfast/extended-iterable';\n\nconst {\n\tONLY_IF_IN_MEMORY_CACHE_FLAG,\n\tNOT_IN_MEMORY_CACHE_FLAG,\n\tALWAYS_CREATE_NEW_BUFFER_FLAG,\n\tFRESH_VERSION_FLAG,\n\tPOPULATE_VERSION_FLAG,\n\tITERATOR_REVERSE_FLAG,\n\tITERATOR_INCLUSIVE_END_FLAG,\n\tITERATOR_EXCLUSIVE_START_FLAG,\n\tITERATOR_INCLUDE_VALUES_FLAG,\n\tITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG,\n\tITERATOR_CONTEXT_IS_TRANSACTION_FLAG,\n} = constants;\nconst KEY_BUFFER_SIZE = 4096;\n\nexport const KEY_BUFFER: BufferWithDataView = createFixedBuffer(KEY_BUFFER_SIZE);\nexport const VALUE_BUFFER: BufferWithDataView = createFixedBuffer(64 * 1024);\n\n/**\n * Backing buffer for the shared iterator state. Layout (Uint32Array view):\n * [0] = key length written into KEY_BUFFER by the most recent iterator step\n * [1] = value length written into VALUE_BUFFER by the most recent step\n */\nexport const ITERATOR_STATE_BUFFER: Buffer = Buffer.allocUnsafeSlow(8);\nexport const ITERATOR_STATE: Uint32Array = new Uint32Array(\n\tITERATOR_STATE_BUFFER.buffer,\n\tITERATOR_STATE_BUFFER.byteOffset,\n\t2\n);\n\nconst MAX_KEY_SIZE = 1024 * 1024; // 1MB\nconst RESET_BUFFER_MODE = 1024;\nconst REUSE_BUFFER_MODE = 512;\nconst SAVE_BUFFER_SIZE = 8192;\n// const WRITE_BUFFER_SIZE = 65536;\n\nexport type StoreContext = NativeDatabase | NativeTransaction;\nexport type StoreGetOptions = GetOptions & DBITransactional;\nexport type StoreIteratorOptions = IteratorOptions & DBITransactional;\nexport type StorePutOptions = PutOptions & DBITransactional;\nexport type StoreRangeOptions = RangeOptions & DBITransactional;\nexport type StoreRemoveOptions = DBITransactional | unknown;\n\nexport type CompactOptions = {\n\tstart?: Key;\n\tend?: Key;\n\t/**\n\t * Compact the bottommost level as well, rewriting every file in range.\n\t *\n\t * RocksDB skips the bottommost level by default when no compaction filter is installed, and\n\t * that is where most of the data sits — so an ordinary `compact()` leaves it untouched. Since a\n\t * changed `compression` algorithm only governs newly written files, rewriting that level is the\n\t * only way to re-encode data that already exists.\n\t *\n\t * This rewrites the whole range regardless of whether RocksDB considers it worth doing, so it\n\t * is as expensive as the data is large. Defaults to `false`.\n\t */\n\tbottommost?: boolean;\n};\n\n/**\n * A RocksDB block/blob compression algorithm. Which algorithms are actually\n * available depends on the libraries the native binding was compiled with —\n * check `supportedCompression` at runtime. `'none'` disables compression and\n * is always available.\n */\nexport type CompressionAlgorithm =\n\t| 'none'\n\t| 'snappy'\n\t| 'zlib'\n\t| 'bzip2'\n\t| 'lz4'\n\t| 'lz4hc'\n\t| 'xpress'\n\t| 'zstd';\n\n/**\n * The `compression` open option: either an algorithm name, or an object with\n * an algorithm and an optional level (forwarded to RocksDB's\n * `compression_opts.level`; meaning is algorithm-specific).\n */\nexport type CompressionOption =\n\t| CompressionAlgorithm\n\t| { algorithm: CompressionAlgorithm; level?: number };\n\n/**\n * The compression currently in effect for a column family, as returned by the\n * `compression` getter. `level` is present only when a non-default compression\n * level is configured.\n */\nexport type CompressionInfo = {\n\talgorithm: CompressionAlgorithm;\n\tlevel?: number;\n};\n\n/**\n * The informational-log settings currently in effect for a database, as\n * returned by the `logOptions` getter. These are database-wide (`DBOptions`)\n * settings, not per-column-family.\n */\nexport type LogOptions = {\n\t/**\n\t * Per-file size cap (bytes) for informational log files (`LOG` /\n\t * `LOG.old.*`).\n\t */\n\tmaxLogFileSize: number;\n\t/**\n\t * Verbosity of informational logging: `0` (debug), `1` (info), `2` (warn),\n\t * `3` (error), `4` (fatal), or `5` (header-only).\n\t */\n\tinfoLogLevel: number;\n};\n\n/**\n * Normalizes the public `compression` option into the primitive fields the\n * native layer expects. When `option` is omitted, or is an object without an\n * `algorithm`, returns an empty object and lets the native layer apply the\n * default (LZ4 when the build supports it, else RocksDB's own default).\n * Throws a `TypeError` for a malformed option and an\n * `Error` for an algorithm that isn't supported by this build.\n */\nexport function normalizeCompression(option: CompressionOption | undefined): {\n\tcompression?: string;\n\tcompressionLevel?: number;\n} {\n\t// When unset, leave compression to the native layer, which defaults to LZ4\n\t// when the build supports it (see Database::Open).\n\tif (option === undefined || option === null) {\n\t\treturn {};\n\t}\n\n\tlet algorithm: string;\n\tlet level: number | undefined;\n\n\tif (typeof option === 'string') {\n\t\talgorithm = option;\n\t} else if (typeof option === 'object' && !Array.isArray(option)) {\n\t\tif (option.algorithm === undefined || option.algorithm === null) {\n\t\t\tif (option.level !== undefined && option.level !== null) {\n\t\t\t\tthrow new TypeError('Compression level cannot be specified without an algorithm');\n\t\t\t}\n\t\t\treturn {};\n\t\t}\n\t\talgorithm = option.algorithm;\n\t\tif (option.level !== undefined && option.level !== null) {\n\t\t\t// TypeScript types `level` as a number. Accept a numeric string too (a\n\t\t\t// common shape from loosely-typed config), but do NOT let bare `Number()`\n\t\t\t// coerce other loose inputs — `true`, `[]`, `[6]`, and `''`/whitespace all\n\t\t\t// become numbers and would silently mis-tune or drop compression. Anything\n\t\t\t// that is not a number or a non-blank numeric string is rejected.\n\t\t\tconst raw = option.level as unknown;\n\t\t\tconst coerced =\n\t\t\t\ttypeof raw === 'number'\n\t\t\t\t\t? raw\n\t\t\t\t\t: typeof raw === 'string' && raw.trim() !== ''\n\t\t\t\t\t\t? Number(raw)\n\t\t\t\t\t\t: Number.NaN;\n\t\t\tif (!Number.isInteger(coerced) || coerced < -2147483648 || coerced > 2147483647) {\n\t\t\t\tthrow new TypeError(\n\t\t\t\t\t`compression level must be a 32-bit integer, got ${JSON.stringify(option.level)}`\n\t\t\t\t);\n\t\t\t}\n\t\t\tlevel = coerced;\n\t\t}\n\t} else {\n\t\tthrow new TypeError('compression must be an algorithm name or an { algorithm, level } object');\n\t}\n\n\tif (!supportedCompression.includes(algorithm)) {\n\t\tthrow new Error(\n\t\t\t`Unsupported compression algorithm \"${algorithm}\". This build supports: ${supportedCompression.join(', ')}`\n\t\t);\n\t}\n\n\treturn { compression: algorithm, compressionLevel: level };\n}\n\n/**\n * Options for the `Store` class.\n */\nexport interface StoreOptions extends Omit<\n\tNativeDatabaseOptions,\n\t'compression' | 'compressionLevel' | 'mode' | 'transactionLogRetentionMs'\n> {\n\t/**\n\t * The block/blob compression algorithm for this column family. Accepts an\n\t * algorithm name (`'lz4'`, `'zstd'`, `'none'`, ...) or an object with an\n\t * `algorithm` and optional `level`. Applies to both SST blocks and blob\n\t * files (large values). Which algorithms are available depends on the native\n\t * build — see `supportedCompression`.\n\t *\n\t * When omitted, defaults to `lz4` if the build supports it, otherwise\n\t * RocksDB's own default (Snappy when linked, else no compression).\n\t * Compression is a dynamically-changeable option: reopening with a\n\t * different algorithm governs subsequently written files; existing files\n\t * keep their compression until rewritten by compaction. Use the\n\t * `compression` getter to read the value currently in effect.\n\t *\n\t * @default 'lz4'\n\t */\n\tcompression?: CompressionOption;\n\n\t/**\n\t * Apply `compression` to every column family in the database, not only the one being opened.\n\t *\n\t * RocksDB opens all of a database's column families in a single native call, and by default\n\t * each of the ones you did not name keeps its persisted algorithm. That is right when codecs\n\t * are chosen per table, but it leaves a caller that wants one codec for the whole database\n\t * unable to say so: those families are already open at their old algorithm before it gets a\n\t * chance to ask, and a column family's compression cannot be changed while it is open.\n\t *\n\t * Setting this applies the requested algorithm to all of them instead — including families\n\t * that were persisted with a different one, which is the point when adopting a codec on a\n\t * database that predates it.\n\t *\n\t * Only meaningful with an explicit `compression` (it throws otherwise), and only on the open\n\t * that actually creates the database handle; later opens of the same path reuse that handle\n\t * and cannot revisit the decision. As always, the algorithm governs newly written files —\n\t * existing SST/blob files keep theirs until rewritten (see `compact({ bottommost: true })`).\n\t *\n\t * @default false\n\t */\n\tcompressionForAllColumnFamilies?: boolean;\n\n\tdecoder?: Encoder | null;\n\tencoder?: Encoder | null;\n\tencoding?: Encoding;\n\tfreezeData?: boolean;\n\tkeyEncoder?: { readKey?: ReadKeyFunction<Key>; writeKey?: WriteKeyFunction };\n\tkeyEncoding?: KeyEncoding;\n\t// mapSize?: number;\n\t// maxDbs?: number;\n\t// maxFreeSpaceToLoad?: number;\n\t// maxFreeSpaceToRetain?: number;\n\t// maxReaders?: number;\n\tmaxKeySize?: number;\n\t// noReadAhead?: boolean;\n\t// noSync?: boolean;\n\t// overlappingSync?: boolean;\n\t// pageSize?: number;\n\tpessimistic?: boolean;\n\n\t/**\n\t * If `true`, the encoder will use a random access structure.\n\t */\n\trandomAccessStructure?: boolean;\n\n\t/**\n\t * When `true`, the database is opened in read-only mode. Write operations\n\t * will throw an error with code `ERR_DATABASE_READONLY`, except for\n\t * `flush()`/`flushSync()`/`compact()`/`compactSync()`, which succeed as\n\t * no-ops.\n\t */\n\treadOnly?: boolean;\n\n\tsharedStructuresKey?: symbol;\n\n\t/**\n\t * A string containing the amount of time or the number of milliseconds to\n\t * retain transaction logs before purging.\n\t *\n\t * @default '3d' (3 days)\n\t */\n\ttransactionLogRetention?: number | string;\n\n\t// trackMetrics?: boolean;\n}\n\n/**\n * Options for the `getUserSharedBuffer()` method.\n */\nexport type UserSharedBufferOptions = { callback?: UserSharedBufferCallback };\n\n/**\n * The return type of `getUserSharedBuffer()`.\n */\nexport type ArrayBufferWithNotify = ArrayBuffer & {\n\tcancel: () => void;\n\tnotify: () => void;\n};\n\n/**\n * A store wraps the `NativeDatabase` binding and database settings so that a\n * single database instance can be shared between the main `RocksDatabase`\n * instance and the `Transaction` instance.\n *\n * A store is bound to a single `RocksDatabase` instance and must not be shared\n * between `RocksDatabase` instances. Each `RocksDatabase` claims its store on\n * construction (see `claim()`); passing a store that another `RocksDatabase`\n * already owns throws. (Sharing with the owning database's `Transaction`\n * instances is expected and allowed.)\n */\nexport class Store {\n\t/**\n\t * Whether a `RocksDatabase` has claimed this store. Durable across\n\t * close/reopen (unlike the handle's open state), so a store reused after its\n\t * owner temporarily closed is still recognized as in-use. See `claim()`.\n\t */\n\t#claimed: boolean = false;\n\n\t/**\n\t * The database instance.\n\t */\n\tdb: NativeDatabase;\n\n\t/**\n\t * The decoder instance. This is commonly the same as the `encoder`\n\t * instance.\n\t */\n\tdecoder: Encoder | null;\n\n\t/**\n\t * Whether the decoder copies the buffer when encoding values.\n\t */\n\tdecoderCopies: boolean = false;\n\n\t/**\n\t * The compression algorithm (or `{ algorithm, level }`) requested for this\n\t * store's column family. Normalized and applied when the database opens.\n\t */\n\tcompression?: CompressionOption;\n\n\t/**\n\t * Whether `compression` applies to every column family in the database rather than just this\n\t * store's. See `RocksDatabaseOptions.compressionForAllColumnFamilies`.\n\t */\n\tcompressionForAllColumnFamilies: boolean = false;\n\n\t/**\n\t * Whether to disable the write ahead log.\n\t */\n\tdisableWAL: boolean;\n\n\t/**\n\t * Whether to enable RocksDB statistics.\n\t */\n\tenableStats: boolean;\n\n\t/**\n\t * Reusable buffer for encoding values using `writeKey()` when the custom\n\t * encoder does not provide a `encode()` method.\n\t */\n\tencodeBuffer: BufferWithDataView;\n\n\t/**\n\t * The encoder instance.\n\t */\n\tencoder: Encoder | null;\n\n\t/**\n\t * The encoding used to encode values. Defaults to `'msgpack'` in\n\t * `RocksDatabase.open()`.\n\t */\n\tencoding: Encoding | null;\n\n\t/**\n\t * Encoder specific option used to signal that the data should be frozen.\n\t */\n\tfreezeData: boolean;\n\n\t/**\n\t * Verbosity of RocksDB's informational logging (`info_log_level`). Omit to\n\t * leave RocksDB's own default.\n\t */\n\tinfoLogLevel?: number;\n\n\t/**\n\t * Reusable buffer for encoding keys.\n\t */\n\tkeyBuffer: BufferWithDataView;\n\n\t/**\n\t * The key encoding to use for keys. Defaults to `'ordered-binary'`.\n\t */\n\tkeyEncoding: KeyEncoding;\n\n\t/**\n\t * The maximum key size.\n\t */\n\tmaxKeySize: number;\n\n\t/**\n\t * Per-file size cap (bytes) for informational log files (`LOG` /\n\t * `LOG.old.*`). Bounds total informational-log footprint to roughly `5 *\n\t * maxLogFileSize` (RocksDB retains up to 5 of these files). A value of `0`\n\t * is RocksDB's \"single unbounded log file\" mode: it disables size-based\n\t * rotation, so the log can grow without limit — set it only if you want that.\n\t *\n\t * @default 16777216 (16MB)\n\t */\n\tmaxLogFileSize?: number;\n\n\t/**\n\t * The maximum number of table files RocksDB keeps open. `0` (the default)\n\t * derives a budget from the effective per-process open-file limit (an\n\t * eighth of the limit — several databases can share one process — clamped\n\t * to `[1024, 262144]`); `-1` holds every table file open (the RocksDB\n\t * default, which can exhaust the process file-descriptor limit when\n\t * compaction falls behind under sustained ingest); a positive `int32` is\n\t * an explicit cap.\n\t */\n\tmaxOpenFiles?: number;\n\n\t/**\n\t * The maximum number of memtables that can be queued per column family\n\t * before writes stall. Higher values absorb write bursts while flushes catch\n\t * up, at the cost of memory.\n\t */\n\tmaxWriteBufferNumber?: number;\n\n\t/**\n\t * The bytes of recent memtable history to retain in memory for transaction\n\t * conflict checking. `-1` derives the value from\n\t * `maxWriteBufferNumber * writeBufferSize`, except under a stalling\n\t * `writeBufferManager`, where it derives `0`: retained history is charged to\n\t * that manager and is only trimmable down to this target, so a target the\n\t * budget cannot hold stalls writes permanently. Set a number to size it\n\t * yourself against the budget and the column-family count.\n\t */\n\tmaxWriteBufferSizeToMaintain?: number;\n\n\t/**\n\t * The total memtable budget in bytes across all column families. When the\n\t * sum of memtables reaches this size, RocksDB flushes the largest one.\n\t * Defaults to `0`, which disables the global trigger so per-CF\n\t * `writeBufferSize` drives flushing.\n\t *\n\t * Set this only if you know your column-family count: it is one budget split\n\t * across all of them, so a value that suits a few families starves many. To\n\t * bound total memtable memory instead, configure a WriteBufferManager.\n\t *\n\t * Database-wide, so it binds when the path is first opened in this process:\n\t * a later open of the same path — including from another worker thread —\n\t * keeps the first opener's value rather than overriding or rejecting it.\n\t */\n\tdbWriteBufferSize?: number;\n\n\t/**\n\t * The name of the store (e.g. the column family). Defaults to `'default'`.\n\t */\n\tname: string;\n\n\t/**\n\t * Whether to disable the block cache.\n\t */\n\tnoBlockCache?: boolean;\n\n\t/**\n\t * The number of threads to use for parallel operations. This is a RocksDB\n\t * option. When undefined, the native layer picks\n\t * `max(1, hardware_concurrency() / 2)`.\n\t */\n\tparallelismThreads?: number;\n\n\t/**\n\t * The path to the database.\n\t */\n\tpath: string;\n\n\t/**\n\t * Whether to use pessimistic locking for transactions. When `true`,\n\t * transactions will fail as soon as a conflict is detected. When `false`,\n\t * transactions will only fail when `commit()` is called.\n\t */\n\tpessimistic: boolean;\n\n\t/**\n\t * Whether the database is open in readonly mode. When `true`, write\n\t * operations will throw an error with code `ERR_DATABASE_READONLY`, except\n\t * for `flush()`/`flushSync()`/`compact()`/`compactSync()`, which succeed as\n\t * no-ops.\n\t */\n\treadOnly: boolean;\n\n\t/**\n\t * Encoder specific flag used to signal that the encoder should use a random\n\t * access structure.\n\t */\n\trandomAccessStructure: boolean;\n\n\t/**\n\t * The function used to encode keys.\n\t */\n\treadKey: ReadKeyFunction<Key>;\n\n\t/**\n\t * The key used to store shared structures.\n\t */\n\tsharedStructuresKey?: symbol;\n\n\t/**\n\t * The level of statistics to capture.\n\t */\n\tstatsLevel?: (typeof stats.StatsLevel)[keyof typeof stats.StatsLevel];\n\n\t/**\n\t * The threshold for the transaction log file's last modified time to be\n\t * older than the retention period before it is rotated to the next sequence\n\t * number. A threshold of 0 means ignore age check.\n\t */\n\ttransactionLogMaxAgeThreshold?: number;\n\n\t/**\n\t * The target maximum size of a transaction log before rotation. Transactions\n\t * are never split across files, so one transaction may exceed this target.\n\t */\n\ttransactionLogMaxSize?: number;\n\n\t/**\n\t * A string containing the amount of time or the number of milliseconds to\n\t * retain transaction logs before purging.\n\t *\n\t * @default '3d' (3 days)\n\t */\n\ttransactionLogRetention?: number | string;\n\n\t/**\n\t * The path to the transaction logs directory.\n\t */\n\ttransactionLogsPath?: string;\n\n\t/**\n\t * Whether this store's column family participates in the VerificationTable.\n\t */\n\tverificationTable?: boolean;\n\n\t/**\n\t * The per-column-family memtable size in bytes at which the memtable is\n\t * sealed and flushed.\n\t */\n\twriteBufferSize?: number;\n\n\t/**\n\t * The function used to encode keys using the shared `keyBuffer`.\n\t */\n\twriteKey: WriteKeyFunction;\n\n\t/**\n\t * Initializes the store with a new `NativeDatabase` instance.\n\t *\n\t * @param path - The path to the database.\n\t * @param options - The options for the store.\n\t */\n\tconstructor(path: string, options?: StoreOptions) {\n\t\tif (!path || typeof path !== 'string') {\n\t\t\tthrow new TypeError('Invalid database path');\n\t\t}\n\n\t\tif (options !== undefined && options !== null && typeof options !== 'object') {\n\t\t\tthrow new TypeError('Database options must be an object');\n\t\t}\n\n\t\tconst { keyEncoding, readKey, writeKey } = initKeyEncoder(\n\t\t\toptions?.keyEncoding,\n\t\t\toptions?.keyEncoder\n\t\t);\n\n\t\tthis.db = new NativeDatabase();\n\t\tthis.compression = options?.compression;\n\t\tthis.compressionForAllColumnFamilies = options?.compressionForAllColumnFamilies === true;\n\t\tthis.dbWriteBufferSize = options?.dbWriteBufferSize;\n\t\tthis.decoder = options?.decoder ?? null;\n\t\tthis.disableWAL = options?.disableWAL ?? false;\n\t\tthis.enableStats = options?.enableStats ?? false;\n\t\tthis.encodeBuffer = createFixedBuffer(SAVE_BUFFER_SIZE);\n\t\tthis.encoder = options?.encoder ?? null;\n\t\tthis.encoding = options?.encoding ?? null;\n\t\tthis.freezeData = options?.freezeData ?? false;\n\t\tthis.infoLogLevel = options?.infoLogLevel;\n\t\tthis.keyBuffer = KEY_BUFFER;\n\t\tthis.keyEncoding = keyEncoding;\n\t\tthis.maxKeySize = options?.maxKeySize ?? MAX_KEY_SIZE;\n\t\tthis.maxLogFileSize = options?.maxLogFileSize;\n\t\tthis.maxOpenFiles = options?.maxOpenFiles;\n\t\tthis.maxWriteBufferNumber = options?.maxWriteBufferNumber;\n\t\tthis.maxWriteBufferSizeToMaintain = options?.maxWriteBufferSizeToMaintain;\n\t\tthis.name = options?.name ?? 'default';\n\t\tthis.noBlockCache = options?.noBlockCache;\n\t\tthis.parallelismThreads = options?.parallelismThreads;\n\t\tthis.path = path;\n\t\tthis.pessimistic = options?.pessimistic ?? false;\n\t\tthis.readOnly = options?.readOnly ?? false;\n\t\tthis.randomAccessStructure = options?.randomAccessStructure ?? false;\n\t\tthis.readKey = readKey;\n\t\tthis.sharedStructuresKey = options?.sharedStructuresKey;\n\t\tthis.statsLevel = options?.statsLevel;\n\t\tthis.transactionLogMaxAgeThreshold = options?.transactionLogMaxAgeThreshold;\n\t\tthis.transactionLogMaxSize = options?.transactionLogMaxSize;\n\t\tthis.transactionLogRetention = options?.transactionLogRetention;\n\t\tthis.transactionLogsPath = options?.transactionLogsPath;\n\t\tthis.verificationTable = options?.verificationTable;\n\t\tthis.writeBufferSize = options?.writeBufferSize;\n\t\tthis.writeKey = writeKey;\n\t}\n\n\t/**\n\t * Closes the database.\n\t */\n\tclose(): void {\n\t\tthis.db.close();\n\t}\n\n\t/**\n\t * Claims this store for a `RocksDatabase`. A store is bound to a single\n\t * database instance, so claiming a store that another `RocksDatabase` has\n\t * already claimed throws. The claim is durable across close/reopen, so a\n\t * store reused after its owner temporarily closed still throws.\n\t */\n\tclaim(): void {\n\t\tif (this.#claimed) {\n\t\t\tthrow new Error('Store is already in use by another RocksDatabase instance');\n\t\t}\n\t\tthis.#claimed = true;\n\t}\n\n\t/**\n\t * Compacts the entire key range of the database asynchronously.\n\t * This triggers manual compaction which removes tombstones and reclaims space.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.compact();\n\t * ```\n\t */\n\tcompact(options?: CompactOptions): Promise<void> {\n\t\tlet startBuffer: Buffer | undefined;\n\t\tlet endBuffer: Buffer | undefined;\n\n\t\tif (options?.start !== undefined) {\n\t\t\tconst start = this.encodeKey(options.start);\n\t\t\tstartBuffer = Buffer.from(start.subarray(start.start, start.end));\n\t\t}\n\t\tif (options?.end !== undefined) {\n\t\t\tconst end = this.encodeKey(options.end);\n\t\t\tendBuffer = Buffer.from(end.subarray(end.start, end.end));\n\t\t}\n\n\t\treturn new Promise((resolve, reject) =>\n\t\t\tthis.db.compact(resolve, reject, startBuffer, endBuffer, options?.bottommost === true)\n\t\t);\n\t}\n\n\t/**\n\t * Creates a backup of the entire database (all column families) into the\n\t * given directory and resolves with the new backup id. Parent directories\n\t * are created as needed. See `backups` for restore and management.\n\t *\n\t * @example\n\t * ```typescript\n\t * const id = await db.backup('/path/to/backups');\n\t * ```\n\t */\n\tasync backup(backupDir: string, options?: BackupOptions): Promise<number>;\n\tasync backup(stream: WritableStream<Uint8Array>, options?: BackupStreamOptions): Promise<void>;\n\tasync backup(\n\t\ttarget: string | WritableStream<Uint8Array>,\n\t\toptions?: BackupOptions | BackupStreamOptions\n\t): Promise<number | void> {\n\t\t// Duck-type rather than `instanceof WritableStream` so a stream from a\n\t\t// different realm (or a polyfill) still routes to the streaming path.\n\t\tif (typeof target !== 'string' && typeof target?.getWriter === 'function') {\n\t\t\treturn backupToStream(this.db, target, options as BackupStreamOptions);\n\t\t}\n\t\t// Refuse to write backup files into the live database directory (or a\n\t\t// subdirectory of it), which would clobber RocksDB's own files.\n\t\tassertBackupDirOutsideDatabase(this.path, target as string);\n\t\t// The native side creates the directory (with missing parents) and holds\n\t\t// the on-disk single-writer lock for the duration of the backup — see\n\t\t// `runCreateBackup` in `src/binding/database/backup.cpp` and\n\t\t// `withBackupDirLock`. Rejects if the directory is already locked.\n\t\treturn new Promise((resolve, reject) =>\n\t\t\tthis.db.backup(resolve, reject, target as string, options as BackupOptions)\n\t\t);\n\t}\n\n\t/**\n\t * Compacts the entire key range of the database synchronously.\n\t * This triggers manual compaction which removes tombstones and reclaims space.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.compactSync();\n\t * ```\n\t */\n\tcompactSync(options?: CompactOptions): void {\n\t\tlet startBuffer: Buffer | undefined;\n\t\tlet endBuffer: Buffer | undefined;\n\n\t\tif (options?.start !== undefined) {\n\t\t\tconst start = this.encodeKey(options.start);\n\t\t\tstartBuffer = Buffer.from(start.subarray(start.start, start.end));\n\t\t}\n\t\tif (options?.end !== undefined) {\n\t\t\tconst end = this.encodeKey(options.end);\n\t\t\tendBuffer = Buffer.from(end.subarray(end.start, end.end));\n\t\t}\n\n\t\tthis.db.compactSync(startBuffer, endBuffer, options?.bottommost === true);\n\t}\n\n\t/**\n\t * Decodes a key from the database.\n\t *\n\t * @param key - The key to decode.\n\t * @returns The decoded key.\n\t */\n\tdecodeKey(key: Buffer): Key {\n\t\treturn this.readKey(key as BufferWithDataView, 0, key.length);\n\t}\n\n\t/**\n\t * Decodes a value from the database.\n\t *\n\t * @param value - The value to decode.\n\t * @returns The decoded value.\n\t */\n\tdecodeValue(value: BufferWithDataView): any {\n\t\tif (value?.length > 0 && typeof this.decoder?.decode === 'function') {\n\t\t\treturn this.decoder.decode(value, { end: value.end });\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Encodes a key for the database.\n\t *\n\t * @param key - The key to encode.\n\t * @returns The encoded key.\n\t */\n\tencodeKey(key: Key): BufferWithDataView {\n\t\tif (key === undefined) {\n\t\t\tthrow new Error('Key is required');\n\t\t}\n\n\t\tconst bytesWritten = this.writeKey(key, this.keyBuffer, 0);\n\t\tif (bytesWritten === 0) {\n\t\t\tthrow new Error('Zero length key is not allowed');\n\t\t}\n\n\t\tthis.keyBuffer.end = bytesWritten;\n\n\t\treturn this.keyBuffer;\n\t}\n\n\t/**\n\t * Encodes a value for the database.\n\t *\n\t * @param value - The value to encode.\n\t * @returns The encoded value.\n\t */\n\tencodeValue(value: any): BufferWithDataView | Uint8Array {\n\t\tif (value && value['\\x10binary-data\\x02']) {\n\t\t\treturn value['\\x10binary-data\\x02'];\n\t\t}\n\n\t\tif (typeof this.encoder?.encode === 'function') {\n\t\t\tif (this.encoder.copyBuffers) {\n\t\t\t\treturn this.encoder.encode(value, REUSE_BUFFER_MODE | RESET_BUFFER_MODE);\n\t\t\t}\n\n\t\t\tconst valueBuffer = this.encoder.encode(value);\n\t\t\tif (typeof valueBuffer === 'string') {\n\t\t\t\treturn Buffer.from(valueBuffer);\n\t\t\t}\n\t\t\treturn valueBuffer;\n\t\t}\n\n\t\tif (typeof value === 'string') {\n\t\t\treturn Buffer.from(value);\n\t\t}\n\n\t\tif (value instanceof Uint8Array) {\n\t\t\treturn value;\n\t\t}\n\n\t\tthrow new Error(`Invalid value put in database (${typeof value}), consider using an encoder`);\n\t}\n\n\tget(\n\t\tcontext: StoreContext,\n\t\tkey: Key,\n\t\talwaysCreateNewBuffer: boolean = false,\n\t\toptions?: StoreGetOptions\n\t): any | undefined {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\tlet flags = 0;\n\t\tif (alwaysCreateNewBuffer) {\n\t\t\t// used by getBinary to force a new safe long-lived buffer\n\t\t\tflags |= ALWAYS_CREATE_NEW_BUFFER_FLAG;\n\t\t}\n\t\tif (options?.populateVersion) {\n\t\t\tflags |= POPULATE_VERSION_FLAG;\n\t\t}\n\t\tconst txnId = this.getTxnId(options);\n\t\tconst expectedVersion = options?.expectedVersion;\n\t\t// getSync is the fast path, which can return immediately if the entry is in memory cache, but we want to fail otherwise\n\t\tconst result = context.getSync(\n\t\t\tkeyParam,\n\t\t\tflags | ONLY_IF_IN_MEMORY_CACHE_FLAG,\n\t\t\ttxnId,\n\t\t\texpectedVersion\n\t\t);\n\t\tif (typeof result === 'number') {\n\t\t\t// return a number indicates it is using the default buffer\n\t\t\tif (result === NOT_IN_MEMORY_CACHE_FLAG) {\n\t\t\t\t// is not in memory cache, use async get since this will involve disk access\n\t\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t\t// We still use the same shared buffer for the key, the native side will make a copy for the async task\n\t\t\t\t\tcontext.get(keyParam, resolve, reject, txnId, expectedVersion);\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (result === FRESH_VERSION_FLAG) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\t// continue with fast path\n\t\t\tVALUE_BUFFER.end = result;\n\t\t\treturn VALUE_BUFFER;\n\t\t} // else it is undefined or it is a new buffer\n\t\treturn result;\n\t}\n\n\t/**\n\t * Estimates the number of keys in a range from RocksDB statistics\n\t * (memtable stats + approximate SST sizes with range-local entry density)\n\t * without iterating. Estimates always reflect committed state, so there is\n\t * no transactional variant.\n\t */\n\testimateCount(options?: CountEstimateOptions): CountEstimate {\n\t\tlet startBuffer: Buffer | undefined;\n\t\tlet endBuffer: Buffer | undefined;\n\t\tconst reverse = options?.reverse ?? false;\n\t\tconst start = reverse ? options?.end : options?.start;\n\t\tconst end = reverse ? options?.start : options?.end;\n\t\tconst exclusiveStart = options?.exclusiveStart ?? reverse;\n\t\tconst inclusiveEnd = options?.inclusiveEnd ?? reverse;\n\n\t\tif (start !== undefined) {\n\t\t\tconst encodedStart = this.encodeKey(start);\n\t\t\t// A zero byte appended to a key is its bytewise successor, turning an\n\t\t\t// inclusive bound into an exclusive one (and vice versa for the end).\n\t\t\tstartBuffer = copyEncodedKey(encodedStart, exclusiveStart);\n\t\t}\n\n\t\tif (end !== undefined) {\n\t\t\tconst encodedEnd = this.encodeKey(end);\n\t\t\tendBuffer = copyEncodedKey(encodedEnd, inclusiveEnd);\n\t\t}\n\n\t\treturn this.db.estimateCount(startBuffer, endBuffer);\n\t}\n\n\tgetCount(context: StoreContext, options?: StoreRangeOptions): number {\n\t\toptions = { ...options };\n\n\t\tif (options?.start !== undefined) {\n\t\t\tconst start = this.encodeKey(options.start);\n\t\t\toptions.start = Buffer.from(start.subarray(start.start, start.end));\n\t\t}\n\n\t\tif (options?.end !== undefined) {\n\t\t\tconst end = this.encodeKey(options.end);\n\t\t\toptions.end = Buffer.from(end.subarray(end.start, end.end));\n\t\t}\n\n\t\treturn context.getCount(options, this.getTxnId(options));\n\t}\n\n\tgetKeys(context: StoreContext, options?: StoreIteratorOptions): any | undefined {\n\t\treturn this.getRange(context, { ...options, values: false }).map((item) => item.key);\n\t}\n\n\tgetKeysCount(context: StoreContext, options?: StoreRangeOptions): number {\n\t\treturn this.getCount(context, options);\n\t}\n\n\tgetRange(\n\t\tcontext: StoreContext,\n\t\toptions?: StoreIteratorOptions\n\t): ExtendedIterable<DBIteratorValue<any>> {\n\t\tif (!this.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\t// Resolve start/end keys, honoring the `key` shortcut for single-key\n\t\t// matches and swapping start/end when iterating in reverse.\n\t\tlet startUnencoded = options?.key ?? options?.start;\n\t\tlet endUnencoded = options?.key ?? options?.end;\n\n\t\tconst includeValues = options?.values ?? true;\n\t\tconst reverse = options?.reverse ?? false;\n\n\t\tlet exclusiveStart = options?.exclusiveStart ?? false;\n\t\tlet inclusiveEnd = options?.inclusiveEnd ?? false;\n\t\tif (options?.key !== undefined) {\n\t\t\tinclusiveEnd = true;\n\t\t}\n\n\t\tif (reverse) {\n\t\t\tconst tmp = startUnencoded;\n\t\t\tstartUnencoded = endUnencoded;\n\t\t\tendUnencoded = tmp;\n\t\t\t// preserve previous default behavior: reverse iteration treats\n\t\t\t// missing exclusiveStart/inclusiveEnd as `true`\n\t\t\texclusiveStart = options?.exclusiveStart ?? true;\n\t\t\tinclusiveEnd = options?.inclusiveEnd ?? true;\n\t\t}\n\n\t\t// Encode both keys back-to-back into the shared key buffer. Each key\n\t\t// is identified to the native side by its (start, end) offsets.\n\t\tconst keyBuffer = this.keyBuffer;\n\t\tlet startKeyEnd = 0;\n\t\tlet endKeyStart = 0;\n\t\tlet endKeyEnd = 0;\n\n\t\tif (startUnencoded !== undefined) {\n\t\t\tstartKeyEnd = this.writeKey(startUnencoded, keyBuffer, 0);\n\t\t\tif (startKeyEnd === 0) {\n\t\t\t\tthrow new Error('Zero length key is not allowed');\n\t\t\t}\n\t\t}\n\n\t\tif (endUnencoded !== undefined) {\n\t\t\tif (endUnencoded === startUnencoded) {\n\t\t\t\t// `key` shortcut: reuse the encoded start key bytes\n\t\t\t\tendKeyStart = 0;\n\t\t\t\tendKeyEnd = startKeyEnd;\n\t\t\t} else {\n\t\t\t\tendKeyStart = startKeyEnd;\n\t\t\t\tendKeyEnd = this.writeKey(endUnencoded, keyBuffer, endKeyStart);\n\t\t\t\tif (endKeyEnd === endKeyStart) {\n\t\t\t\t\tthrow new Error('Zero length key is not allowed');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet flags = 0;\n\t\tif (reverse) flags |= ITERATOR_REVERSE_FLAG;\n\t\tif (exclusiveStart) flags |= ITERATOR_EXCLUSIVE_START_FLAG;\n\t\tif (inclusiveEnd) flags |= ITERATOR_INCLUSIVE_END_FLAG;\n\t\tif (includeValues) flags |= ITERATOR_INCLUDE_VALUES_FLAG;\n\t\tif (includeValues && !this.decoderCopies) {\n\t\t\tflags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;\n\t\t}\n\t\t// Tell the native constructor whether `context` is a Transaction (vs.\n\t\t// the database) so it can skip a napi_instanceof check. The store\n\t\t// holds the canonical NativeDatabase reference, so identity comparison\n\t\t// is sufficient.\n\t\tif (context !== this.db) {\n\t\t\tflags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;\n\t\t}\n\n\t\t// Only pass the advanced ReadOptions object on the rare path where any\n\t\t// of the underlying RocksDB iterator options are actually overridden.\n\t\tconst advancedOptions =\n\t\t\toptions !== undefined &&\n\t\t\t(options.adaptiveReadahead !== undefined ||\n\t\t\t\toptions.asyncIO !== undefined ||\n\t\t\t\toptions.autoReadaheadSize !== undefined ||\n\t\t\t\toptions.backgroundPurgeOnIteratorCleanup !== undefined ||\n\t\t\t\toptions.fillCache !== undefined ||\n\t\t\t\toptions.readaheadSize !== undefined ||\n\t\t\t\toptions.tailing !== undefined)\n\t\t\t\t? options\n\t\t\t\t: undefined;\n\n\t\treturn new ExtendedIterable(\n\t\t\t// @ts-expect-error ExtendedIterable v1 constructor type definition is incorrect\n\t\t\tnew DBIterator(\n\t\t\t\tnew NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions),\n\t\t\t\tthis,\n\t\t\t\tincludeValues,\n\t\t\t\toptions?.limit\n\t\t\t)\n\t\t);\n\t}\n\n\tgetSync(\n\t\tcontext: StoreContext,\n\t\tkey: Key,\n\t\talwaysCreateNewBuffer: boolean = false,\n\t\toptions?: StoreGetOptions\n\t): any | undefined {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\tlet flags = 0;\n\t\tif (alwaysCreateNewBuffer) {\n\t\t\tflags |= ALWAYS_CREATE_NEW_BUFFER_FLAG;\n\t\t}\n\t\tif (options?.populateVersion) {\n\t\t\tflags |= POPULATE_VERSION_FLAG;\n\t\t}\n\t\t// we are using the shared buffer for keys, so we just pass in the key ending point (much faster than passing in a buffer)\n\t\tconst result = context.getSync(\n\t\t\tkeyParam,\n\t\t\tflags,\n\t\t\tthis.getTxnId(options),\n\t\t\toptions?.expectedVersion\n\t\t);\n\t\tif (typeof result === 'number') {\n\t\t\tif (result === FRESH_VERSION_FLAG) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\t// return a number indicates it is using the default buffer\n\t\t\tVALUE_BUFFER.end = result;\n\t\t\treturn VALUE_BUFFER;\n\t\t} // else it is undefined or it is a new buffer\n\t\treturn result;\n\t}\n\n\t/**\n\t * Checks if the data method options object contains a transaction ID and\n\t * returns it.\n\t */\n\tgetTxnId(options?: DBITransactional | unknown): number | undefined {\n\t\tlet txnId: number | undefined;\n\t\tif (!this.readOnly && (options as DBITransactional)?.transaction) {\n\t\t\ttxnId = (options as DBITransactional).transaction!.id;\n\t\t\tif (txnId === undefined) {\n\t\t\t\tthrow new TypeError('Invalid transaction');\n\t\t\t}\n\t\t}\n\t\treturn txnId;\n\t}\n\n\t/**\n\t * Gets or creates a buffer that can be shared across worker threads.\n\t *\n\t * @param key - The key to get or create the buffer for.\n\t * @param defaultBuffer - The default buffer to copy and use if the buffer\n\t * does not exist.\n\t * @param [options] - The options for the buffer.\n\t * @param [options.callback] - A optional callback is called when `notify()`\n\t * on the returned buffer is called.\n\t * @returns An `ArrayBuffer` that is internally backed by a rocksdb-js\n\t * managed buffer. The buffer also has `notify()` and `cancel()` methods\n\t * that can be used to notify the specified `options.callback`.\n\t */\n\tgetUserSharedBuffer(\n\t\tkey: Key,\n\t\tdefaultBuffer: ArrayBuffer,\n\t\toptions?: UserSharedBufferOptions\n\t): ArrayBufferWithNotify {\n\t\tconst encodedKey = this.encodeKey(key);\n\n\t\tif (options !== undefined && typeof options !== 'object') {\n\t\t\tthrow new TypeError('Options must be an object');\n\t\t}\n\n\t\tconst buffer = this.db.getUserSharedBuffer(\n\t\t\tencodedKey,\n\t\t\tdefaultBuffer,\n\t\t\toptions?.callback\n\t\t) as ArrayBufferWithNotify;\n\n\t\t// note: the notification methods need to re-encode the key because\n\t\t// encodeKey() uses a shared key buffer\n\t\tbuffer.notify = (...args: any[]) => {\n\t\t\treturn this.db.notify(this.encodeKey(key), args);\n\t\t};\n\t\tbuffer.cancel = () => {\n\t\t\tif (options?.callback) {\n\t\t\t\tthis.db.removeListener(this.encodeKey(key), options.callback);\n\t\t\t}\n\t\t};\n\t\treturn buffer;\n\t}\n\n\t/**\n\t * Checks if a lock exists.\n\t * @param key The lock key.\n\t * @returns `true` if the lock exists, `false` otherwise\n\t */\n\thasLock(key: Key): boolean {\n\t\treturn this.db.hasLock(this.encodeKey(key));\n\t}\n\n\t/**\n\t * Checks if the database is open.\n\t *\n\t * @returns `true` if the database is open, `false` otherwise.\n\t */\n\tisOpen(): boolean {\n\t\treturn this.db.opened;\n\t}\n\n\t/**\n\t * Lists all transaction log names.\n\t *\n\t * @returns an array of transaction log names.\n\t */\n\tlistLogs(): string[] {\n\t\treturn this.db.listLogs();\n\t}\n\n\t/**\n\t * Opens the database. This must be called before any database operations\n\t * are performed.\n\t */\n\topen(): boolean {\n\t\tif (this.db.opened) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst { compression, compressionLevel } = normalizeCompression(this.compression);\n\n\t\tthis.db.open(this.path, {\n\t\t\tcompression,\n\t\t\tcompressionLevel,\n\t\t\tcompressionForAllColumnFamilies: this.compressionForAllColumnFamilies,\n\t\t\tdbWriteBufferSize: this.dbWriteBufferSize,\n\t\t\tdisableWAL: this.disableWAL,\n\t\t\tenableStats: this.enableStats,\n\t\t\tinfoLogLevel: this.infoLogLevel,\n\t\t\tmaxLogFileSize: this.maxLogFileSize,\n\t\t\tmaxOpenFiles: this.maxOpenFiles,\n\t\t\tmaxWriteBufferNumber: this.maxWriteBufferNumber,\n\t\t\tmaxWriteBufferSizeToMaintain: this.maxWriteBufferSizeToMaintain,\n\t\t\tmode: this.pessimistic ? 'pessimistic' : 'optimistic',\n\t\t\tname: this.name,\n\t\t\tnoBlockCache: this.noBlockCache,\n\t\t\tparallelismThreads: this.parallelismThreads,\n\t\t\treadOnly: this.readOnly,\n\t\t\tstatsLevel: this.statsLevel,\n\t\t\ttransactionLogMaxAgeThreshold: this.transactionLogMaxAgeThreshold,\n\t\t\ttransactionLogMaxSize: this.transactionLogMaxSize,\n\t\t\ttransactionLogRetentionMs: this.transactionLogRetention\n\t\t\t\t? parseDuration(this.transactionLogRetention)\n\t\t\t\t: undefined,\n\t\t\ttransactionLogsPath: this.transactionLogsPath,\n\t\t\tverificationTable: this.verificationTable,\n\t\t\twriteBufferSize: this.writeBufferSize,\n\t\t});\n\n\t\treturn false;\n\t}\n\n\tputSync(context: StoreContext, key: Key, value: any, options?: StorePutOptions): void {\n\t\tif (!this.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\t// IMPORTANT!\n\t\t// We MUST encode the value before the key because if the `sharedStructuresKey`\n\t\t// is set, it will be used by `getStructures()` and `saveStructures()` which in\n\t\t// turn will encode the `sharedStructuresKey` into the shared `keyBuffer`\n\t\t// overwriting this method's encoded key!\n\t\tconst valueBuffer = this.encodeValue(value);\n\n\t\tcontext.putSync(this.encodeKey(key), valueBuffer, this.getTxnId(options));\n\t}\n\n\tremoveSync(context: StoreContext, key: Key, options?: StoreRemoveOptions): void {\n\t\tif (!this.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\tcontext.removeSync(this.encodeKey(key), this.getTxnId(options));\n\t}\n\n\t/**\n\t * Attempts to acquire a lock for a given key. If the lock is available,\n\t * the function returns `true` and the optional callback is never called.\n\t * If the lock is not available, the function returns `false` and the\n\t * callback is queued until the lock is released.\n\t *\n\t * @param key - The key to lock.\n\t * @param onUnlocked - A callback to call when the lock is released.\n\t * @returns `true` if the lock was acquired, `false` otherwise.\n\t */\n\ttryLock(key: Key, onUnlocked?: () => void): boolean {\n\t\tif (onUnlocked !== undefined && typeof onUnlocked !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\treturn this.db.tryLock(this.encodeKey(key), onUnlocked);\n\t}\n\n\t/**\n\t * Releases the lock on the given key and calls any queued `onUnlocked`\n\t * callback handlers.\n\t *\n\t * @param key - The key to unlock.\n\t */\n\tunlock(key: Key): void {\n\t\treturn this.db.unlock(this.encodeKey(key));\n\t}\n\n\t/**\n\t * Gets or creates a transaction log instance.\n\t *\n\t * @param context - The context to use for the transaction log.\n\t * @param name - The name of the transaction log.\n\t * @returns The transaction log.\n\t */\n\tuseLog(context: StoreContext, name: string | number): TransactionLog {\n\t\tif (typeof name !== 'string' && typeof name !== 'number') {\n\t\t\tthrow new TypeError('Log name must be a string or number');\n\t\t}\n\t\tif (typeof name === 'string' && /[\\t\\n\\r\\\\/]/.test(name)) {\n\t\t\tthrow new Error(`Invalid transaction log name \"${name}\"`);\n\t\t}\n\t\t// Pass the JS database per-call: the native transaction deliberately\n\t\t// holds no napi_ref to it (HarperFast/rocksdb-js#741); the database\n\t\t// context ignores the extra argument.\n\t\treturn context.useLog(String(name), this.db);\n\t}\n\n\t/**\n\t * Checks the process-global verification table for a fresh version match\n\t * on `key`. Returns `true` when the table currently records `version` for\n\t * this database+column-family. Provides a fast cache-freshness check\n\t * before falling back to a full read.\n\t */\n\tverifyVersion(key: Key, version: number): boolean {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\treturn this.db.verifyVersion(keyParam, version);\n\t}\n\n\t/**\n\t * Seeds the verification-table slot for `key` with `version`. Has no\n\t * effect if the slot is currently lock-tagged or the table is disabled.\n\t * Useful after a full read where the caller already knows the version.\n\t */\n\tpopulateVersion(key: Key, version: number): void {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\tthis.db.populateVersion(keyParam, version);\n\t}\n\n\t/**\n\t * Acquires a lock on the given key and calls the callback.\n\t *\n\t * @param key - The key to lock.\n\t * @param callback - The callback to call when the lock is acquired.\n\t * @returns A promise that resolves when the lock is acquired.\n\t */\n\twithLock(key: Key, callback: () => void | Promise<void>): Promise<void> {\n\t\tif (typeof callback !== 'function') {\n\t\t\treturn Promise.reject(new TypeError('Callback must be a function'));\n\t\t}\n\n\t\treturn this.db.withLock(this.encodeKey(key), callback);\n\t}\n}\n\n/**\n * Copies an encoded key out of the shared key buffer (which the next\n * `encodeKey` call would clobber), optionally appending a zero byte to\n * produce the key's bytewise successor.\n */\nfunction copyEncodedKey(encoded: BufferWithDataView, appendSuccessorByte: boolean): Buffer {\n\tconst length = encoded.end - encoded.start;\n\tconst copy = Buffer.allocUnsafe(length + (appendSuccessorByte ? 1 : 0));\n\tcopy.set(encoded.subarray(encoded.start, encoded.end));\n\tif (appendSuccessorByte) {\n\t\tcopy[length] = 0;\n\t}\n\treturn copy;\n}\n\n/**\n * Ensure that they key has been copied into our shared buffer, and return the ending position\n * @param keyBuffer\n */\nfunction getKeyParam(keyBuffer: BufferWithDataView): number | Buffer {\n\tif (keyBuffer.buffer === KEY_BUFFER.buffer) {\n\t\tif (keyBuffer.end >= 0) {\n\t\t\treturn keyBuffer.end;\n\t\t}\n\t\tif (keyBuffer.byteOffset === 0) {\n\t\t\treturn keyBuffer.byteLength;\n\t\t}\n\t}\n\tif (keyBuffer.length > KEY_BUFFER.length) {\n\t\t// for larger key buffers, we pass it straight in\n\t\treturn keyBuffer;\n\t}\n\tKEY_BUFFER.set(keyBuffer);\n\treturn keyBuffer.length;\n}\n\nexport interface GetOptions {\n\t/**\n\t * When set, the native layer checks the verification table before reading.\n\t * If the slot holds this version, returns `FRESH_VERSION_FLAG` immediately\n\t * (the cached value is still valid). After a DB read, also seeds the slot\n\t * with the version extracted from the value.\n\t */\n\texpectedVersion?: number;\n\n\t/**\n\t * When `true`, after a DB read the native layer automatically seeds the\n\t * verification-table slot with the version extracted from the value.\n\t * Eliminates the need for a separate `populateVersion` call on cold reads.\n\t *\n\t * @default false\n\t */\n\tpopulateVersion?: boolean;\n\n\t/**\n\t * Whether to skip decoding the value.\n\t *\n\t * @default false\n\t */\n\tskipDecode?: boolean;\n}\n\nexport interface PutOptions {\n\tappend?: boolean;\n\tinstructedWrite?: boolean;\n\tnoDupData?: boolean;\n\tnoOverwrite?: boolean;\n}\n","import { DBI } from './dbi.ts';\nimport { constants, NativeTransaction, type NativeTransactionOptions } from './load-binding.ts';\nimport { Store } from './store.ts';\n\n/**\n * Sentinel value returned by `commit()` when `coordinatedRetry: true` and the\n * transaction encountered an IsBusy conflict. The native layer parks on VT\n * slots and resolves only after the conflicting transaction releases its write\n * intent, so callers should retry immediately without any backoff delay.\n */\nexport const RETRY_NOW: number = constants.RETRY_NOW_VALUE;\n\nexport class TransactionAlreadyAbortedError extends Error {\n\treadonly code = 'ERR_ALREADY_ABORTED';\n}\n\n/**\n * Base for commit conflicts the native layer has already recovered from by resetting the\n * transaction in place (fresh RocksDB snapshot; `committedPosition` preserved, so a staged\n * transaction-log batch stays write-once): the caller should re-run the transaction body\n * and retry the commit — the handling is identical for every subclass. `hasLog` reports\n * whether the transaction wrote to a transaction log (drives the default retry decision).\n *\n * {@link TransactionAbandonedError} shares this field shape but deliberately does NOT\n * extend this class — an abandoned transaction is not retryable, and retryability is the\n * boundary this hierarchy expresses.\n */\nexport class TransactionRetryableError extends Error {\n\treadonly hasLog: boolean;\n\treadonly txn: Transaction;\n\n\tconstructor(error: Error, txn: Transaction) {\n\t\tsuper(error.message);\n\t\tthis.hasLog = (error as Error & { hasLog?: boolean }).hasLog ?? false;\n\t\tthis.txn = txn;\n\t}\n}\n\n/**\n * An optimistic commit detected a write conflict with a concurrently committed\n * transaction (RocksDB `Busy`).\n */\nexport class TransactionIsBusyError extends TransactionRetryableError {\n\treadonly code = 'ERR_BUSY';\n}\n\n/**\n * An optimistic commit could not be validated: the transaction's snapshot was stranded\n * outside the memtable window (its sequence history was flushed away — RocksDB\n * `TryAgain`), so the conflict check had nothing to validate against.\n */\nexport class TransactionTryAgainError extends TransactionRetryableError {\n\treadonly code = 'ERR_TRY_AGAIN';\n}\n\nexport class TransactionAbandonedError extends Error {\n\treadonly code = 'ERR_TRANSACTION_ABANDONED';\n\treadonly hasLog: boolean;\n\treadonly txn: Transaction;\n\n\tconstructor(error: Error, txn: Transaction) {\n\t\tsuper(error.message);\n\t\tthis.hasLog = (error as Error & { hasLog?: boolean }).hasLog ?? false;\n\t\tthis.txn = txn;\n\t}\n}\n\n/**\n * Provides transaction level operations to a transaction callback.\n */\nexport class Transaction extends DBI {\n\t#txn: NativeTransaction;\n\n\t/**\n\t * Create a new transaction.\n\t *\n\t * @param store - The base store interface for this transaction.\n\t * @param options - The options for the transaction.\n\t */\n\tconstructor(store: Store, options?: NativeTransactionOptions) {\n\t\tif (store.readOnly) {\n\t\t\tsuper(store);\n\t\t\tthis.#txn = { id: 0 } as NativeTransaction;\n\t\t\tthis.abandonWrites = this.abort = this.commitSync = this.setTimestamp = () => {};\n\t\t\tthis.commit = async () => {};\n\t\t\tthis.getTimestamp = () => 0;\n\t\t} else {\n\t\t\tconst txn = new NativeTransaction(store.db, options);\n\t\t\tsuper(store, txn);\n\t\t\tthis.#txn = txn;\n\t\t}\n\t}\n\n\t/**\n\t * Release the staged writes' verification-table write intents without\n\t * closing the transaction, barring any later commit or write. For a\n\t * transaction kept open only for its outstanding read iterators after the\n\t * writes were replayed onto another transaction: otherwise other writers'\n\t * coordinated-retry commits park on those intents until it is aborted.\n\t * Reads keep working, including read-your-own-writes.\n\t */\n\tabandonWrites(): void {\n\t\tthis.#txn.abandonWrites();\n\t}\n\n\t/**\n\t * Abort the transaction.\n\t */\n\tabort(): void {\n\t\ttry {\n\t\t\tthis.#txn.abort();\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_TRANSACTION_ABANDONED') {\n\t\t\t\tthrow new TransactionAbandonedError(err, this);\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\t/**\n\t * Commit the transaction.\n\t *\n\t * Returns `RETRY_NOW` when `coordinatedRetry: true` and an IsBusy conflict\n\t * was detected. The caller should retry the transaction body immediately.\n\t */\n\tasync commit(): Promise<typeof RETRY_NOW | void> {\n\t\ttry {\n\t\t\tconst result = await new Promise<number | void>((resolve, reject) => {\n\t\t\t\tthis.notify('beforecommit');\n\t\t\t\tthis.#txn.commit(resolve, reject);\n\t\t\t});\n\t\t\tif (result === RETRY_NOW) {\n\t\t\t\treturn RETRY_NOW;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthrow this.#handleCommitError(err);\n\t\t} finally {\n\t\t\tthis.notify('aftercommit', { next: null, last: null, txnId: this.#txn.id });\n\t\t}\n\t}\n\n\t/**\n\t * Commit the transaction synchronously.\n\t */\n\tcommitSync(): void {\n\t\ttry {\n\t\t\tthis.notify('beforecommit');\n\t\t\tthis.#txn.commitSync();\n\t\t} catch (err) {\n\t\t\tthrow this.#handleCommitError(err);\n\t\t} finally {\n\t\t\tthis.notify('aftercommit', { next: null, last: null, txnId: this.#txn.id });\n\t\t}\n\t}\n\n\t/**\n\t * Detect if error is an already aborted or busy error and return the appropriate error class.\n\t *\n\t * @param err - The error to check.\n\t * @returns The specialized error.\n\t */\n\t#handleCommitError(err: unknown): Error {\n\t\tif (err instanceof Error && 'code' in err) {\n\t\t\tif (err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\treturn new TransactionAlreadyAbortedError(err.message);\n\t\t\t}\n\t\t\tif (err.code === 'ERR_BUSY') {\n\t\t\t\treturn new TransactionIsBusyError(err, this);\n\t\t\t}\n\t\t\tif (err.code === 'ERR_TRY_AGAIN') {\n\t\t\t\treturn new TransactionTryAgainError(err, this);\n\t\t\t}\n\t\t}\n\t\treturn err as Error;\n\t}\n\n\t/**\n\t * Returns the transaction start timestamp in seconds. Defaults to the time at which\n\t * the transaction was created.\n\t *\n\t * @returns The transaction start timestamp in seconds.\n\t */\n\tgetTimestamp(): number {\n\t\treturn this.#txn.getTimestamp();\n\t}\n\n\t/**\n\t * Get the transaction id.\n\t */\n\tget id(): number {\n\t\treturn this.#txn.id;\n\t}\n\n\t/**\n\t * Set the transaction start timestamp in seconds.\n\t *\n\t * @param timestamp - The timestamp to set in seconds.\n\t */\n\tsetTimestamp(timestamp?: number): void {\n\t\tthis.#txn.setTimestamp(timestamp);\n\t}\n}\n","import type { BackupStreamOptions } from './backup-stream.ts';\nimport type { BackupOptions } from './backup.ts';\nimport { CountEstimator, type CountEstimatorOptions } from './count-estimator.ts';\nimport {\n\tDBI,\n\ttype CountEstimate,\n\ttype CountEstimateOptions,\n\ttype DBITransactional,\n} from './dbi.ts';\nimport type { BufferWithDataView, Encoder, EncoderFunction, Key } from './encoding.ts';\nimport {\n\taddGlobalListener,\n\tconfig,\n\tglobalListenerCount,\n\tglobalNotify,\n\tremoveGlobalListener,\n\ttype BackgroundError,\n\ttype BackgroundErrorOptions,\n\ttype FlushOptions,\n\ttype PurgedLog,\n\ttype PurgeLogsOptions,\n\ttype RocksDatabaseConfig,\n\ttype NativeTransactionOptions,\n} from './load-binding.ts';\nimport type { StatsAll, StatsDefault, StatsValue } from './stats.ts';\nimport {\n\ttype ArrayBufferWithNotify,\n\ttype CompactOptions,\n\ttype CompressionInfo,\n\tITERATOR_STATE_BUFFER,\n\tKEY_BUFFER,\n\ttype LogOptions,\n\tStore,\n\ttype StoreOptions,\n\ttype UserSharedBufferOptions,\n\tVALUE_BUFFER,\n} from './store.ts';\nimport {\n\tRETRY_NOW,\n\tTransaction,\n\tTransactionAbandonedError,\n\tTransactionAlreadyAbortedError,\n\tTransactionRetryableError,\n} from './transaction.ts';\nimport { Encoder as MsgpackEncoder } from 'msgpackr';\nimport { existsSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport * as orderedBinary from 'ordered-binary';\n\nexport type TransactionCallback<T> = (txn: Transaction, attempt: number) => T | PromiseLike<T>;\n\nexport interface RocksDatabaseOptions extends StoreOptions {\n\t/**\n\t * The column family name.\n\t *\n\t * @default 'default'\n\t */\n\tname?: string;\n}\n\nexport interface TransactionOptions extends NativeTransactionOptions {\n\t/**\n\t * The maximum number of times to retry the transaction.\n\t *\n\t * @default 3\n\t */\n\tmaxRetries?: number;\n\n\t/**\n\t * Whether to retry the transaction if it fails with `IsBusy`.\n\t *\n\t * @default `true` when the transaction is bound to a transaction log, otherwise `false`\n\t */\n\tretryOnBusy?: boolean;\n}\n\nexport type RocksDBStat = StatsValue;\nexport type RocksDBStats = StatsDefault | StatsAll;\n\n// Mirrors the native `backgroundErrorSeverityName` (core/background_error) so\n// setLastError can derive a severityName from a bare severity.\nconst BACKGROUND_ERROR_SEVERITY_NAMES = ['none', 'soft', 'hard', 'fatal', 'unrecoverable'];\nfunction backgroundErrorSeverityName(severity: number): string {\n\treturn BACKGROUND_ERROR_SEVERITY_NAMES[severity] ?? 'unknown';\n}\n\n/**\n * The main class for interacting with a RocksDB database.\n *\n * Before using this class, you must open the database first.\n *\n * @example\n * ```typescript\n * const db = RocksDatabase.open('/path/to/database');\n * await db.put('key', 'value');\n * const value = await db.get('key');\n * db.close();\n * ```\n */\nexport class RocksDatabase extends DBI<DBITransactional> {\n\t/**\n\t * The name of the database.\n\t */\n\t#name: string;\n\n\tconstructor(pathOrStore: string | Store, options?: RocksDatabaseOptions) {\n\t\t// A store is bound to a single RocksDatabase instance. Each database claims\n\t\t// its store on construction; passing a store another database already owns\n\t\t// throws (see Store#claim).\n\t\tlet store: Store;\n\t\tif (typeof pathOrStore === 'string') {\n\t\t\tstore = new Store(pathOrStore, options);\n\t\t} else if (pathOrStore instanceof Store) {\n\t\t\tstore = pathOrStore;\n\t\t} else {\n\t\t\tthrow new TypeError('Invalid database path or store');\n\t\t}\n\t\tstore.claim();\n\t\tsuper(store);\n\t\tthis.#name = options?.name ?? 'default';\n\t}\n\n\t/**\n\t * Removes all data from the database asynchronously.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.clear();\n\t * ```\n\t */\n\tclear(): Promise<void> {\n\t\tif (this.store.encoder?.structures !== undefined) {\n\t\t\tthis.store.encoder.structures = [];\n\t\t}\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.store.db.clear(resolve, reject);\n\t\t});\n\t}\n\n\t/**\n\t * Removes all entries from the database synchronously.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.clearSync();\n\t * ```\n\t */\n\tclearSync(): void {\n\t\tif (this.store.encoder?.structures !== undefined) {\n\t\t\tthis.store.encoder.structures = [];\n\t\t}\n\n\t\tthis.store.db.clearSync();\n\t}\n\n\t/**\n\t * Closes the database.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.close();\n\t * ```\n\t */\n\tclose(): void {\n\t\tthis.store.close();\n\t}\n\n\t/**\n\t * Compacts the entire key range of the database asynchronously.\n\t * This triggers manual compaction which removes tombstones and reclaims space.\n\t *\n\t * On a read-only database this is a no-op: arguments are still validated, but\n\t * the returned promise resolves without compacting rather than rejecting.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.compact();\n\t * ```\n\t */\n\tcompact(options?: CompactOptions): Promise<void> {\n\t\treturn this.store.compact(options);\n\t}\n\n\t/**\n\t * Creates a backup of the entire database (all column families) into the\n\t * given directory, creating parent directories as needed, and resolves with\n\t * the new backup id. Use the `backups` namespace to restore, list, delete,\n\t * purge, or verify backups.\n\t *\n\t * When the database was opened with `disableWAL`, the memtable is flushed\n\t * before the backup by default so unflushed data is not lost.\n\t *\n\t * @example\n\t * ```typescript\n\t * import { backups } from '@harperfast/rocksdb-js';\n\t *\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const id = await db.backup('/path/to/backups');\n\t * ```\n\t */\n\tbackup(backupDir: string, options?: BackupOptions): Promise<number>;\n\t/**\n\t * Streams a consistent snapshot of the entire database to a `WritableStream`\n\t * as a tar archive, with no intermediate copy written to disk. Resolves once\n\t * the stream has been fully written and closed.\n\t *\n\t * Backpressure is honored end to end, so a slow consumer (e.g. a network or\n\t * S3 upload) paces the backup rather than buffering it in memory. The archive\n\t * unpacks with any tar tool into a directory that opens as a RocksDB database.\n\t *\n\t * @example\n\t * ```typescript\n\t * const file = await fetch(uploadUrl, { method: 'PUT', body: stream });\n\t * await db.backup(stream); // `stream` is the request's WritableStream\n\t * ```\n\t */\n\tbackup(stream: WritableStream<Uint8Array>, options?: BackupStreamOptions): Promise<void>;\n\tbackup(\n\t\ttarget: string | WritableStream<Uint8Array>,\n\t\toptions?: BackupOptions | BackupStreamOptions\n\t): Promise<number | void> {\n\t\tif (typeof target === 'string') {\n\t\t\treturn this.store.backup(target, options as BackupOptions);\n\t\t}\n\t\treturn this.store.backup(target, options as BackupStreamOptions);\n\t}\n\n\t/**\n\t * Creates a hardlinked, point-in-time, fully independent copy of the entire\n\t * database (all column families) at `targetPath` and resolves once written.\n\t *\n\t * Unlike a backup, a checkpoint is a normal, writable sibling database: open\n\t * it with {@link RocksDatabase.open} and it diverges independently from the\n\t * source. SST and blob files are hardlinked when `targetPath` is on the same\n\t * filesystem as the database and copied otherwise (other files such as the\n\t * MANIFEST are always copied), so the operation is near-instant on the same\n\t * filesystem. The memtable is flushed so the checkpoint includes the latest\n\t * writes even when the WAL is disabled.\n\t *\n\t * Parent directories are created as needed. `targetPath` itself must not\n\t * already exist (RocksDB creates the checkpoint directory) and rejects with\n\t * `Create checkpoint failed: target path exists` if it does. The caller is\n\t * responsible for eventual cleanup of the directory.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.createCheckpoint('/path/to/checkpoint');\n\t * const branch = RocksDatabase.open('/path/to/checkpoint');\n\t * ```\n\t */\n\tcreateCheckpoint(targetPath: string): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tif (existsSync(targetPath)) {\n\t\t\t\treject(new Error('Create checkpoint failed: target path exists'));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Create parent directories as needed (a throw here rejects the promise),\n\t\t\t// then hand off to the native worker synchronously so it registers its\n\t\t\t// in-flight operation before this call returns.\n\t\t\tmkdirSync(dirname(targetPath), { recursive: true });\n\t\t\tthis.store.db.createCheckpoint(resolve, reject, targetPath);\n\t\t});\n\t}\n\n\t/**\n\t * Compacts the entire key range of the database synchronously.\n\t * This triggers manual compaction which removes tombstones and reclaims space.\n\t *\n\t * On a read-only database this validates its arguments and then returns\n\t * without compacting, rather than throwing.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.compactSync();\n\t * ```\n\t */\n\tcompactSync(options?: CompactOptions): void {\n\t\treturn this.store.compactSync(options);\n\t}\n\n\t/**\n\t * Returns the list of column families in the RocksDB database.\n\t */\n\tget columns(): string[] {\n\t\treturn this.store.db.columns;\n\t}\n\n\t/**\n\t * The compression currently in effect for this database's column family, read\n\t * live from RocksDB, as `{ algorithm, level? }`. `algorithm` is a friendly\n\t * name (e.g. `'lz4'`, `'zstd'`, `'none'`); `level` is present only when a\n\t * non-default compression level is set. The database must be open. Defaults to\n\t * LZ4 when the native build supports it.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/db', { compression: { algorithm: 'zstd', level: 3 } });\n\t * db.compression; // { algorithm: 'zstd', level: 3 }\n\t * ```\n\t */\n\tget compression(): CompressionInfo {\n\t\treturn this.store.db.getCompression() as CompressionInfo;\n\t}\n\n\t/**\n\t * The informational-log settings currently in effect for this database,\n\t * read live from RocksDB, as `{ maxLogFileSize, infoLogLevel }`. These are\n\t * database-wide settings (not per-column-family): `maxLogFileSize` bounds\n\t * each retained `LOG` / `LOG.old.*` file's size (defaults to 16MB, so with\n\t * RocksDB's `keep_log_file_num = 5` the total footprint is bounded at\n\t * roughly 80MB); `infoLogLevel` is the logging verbosity. The database must\n\t * be open.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/db', { maxLogFileSize: 4 * 1024 * 1024 });\n\t * db.logOptions; // { maxLogFileSize: 4194304, infoLogLevel: 1 }\n\t * ```\n\t */\n\tget logOptions(): LogOptions {\n\t\treturn this.store.db.getLogOptions() as LogOptions;\n\t}\n\n\t/**\n\t * Set global database settings.\n\t *\n\t * @param options - The options for the database.\n\t *\n\t * @example\n\t * ```typescript\n\t * RocksDatabase.config({ blockCacheSize: 1024 * 1024 });\n\t * ```\n\t */\n\tstatic config(options: RocksDatabaseConfig): void {\n\t\tconfig(options);\n\t}\n\n\t/**\n\t * Registers a process-wide event listener. Internal events emitted by the\n\t * native binding use namespaced keys (e.g. `'transactionLog:warning'`).\n\t *\n\t * Listeners are not tied to any specific database — they fire for every\n\t * matching event emitted in this process.\n\t *\n\t * @example\n\t * ```typescript\n\t * RocksDatabase.on('transactionLog:warning', (warning) => {\n\t * console.warn(warning);\n\t * });\n\t * ```\n\t */\n\tstatic on(event: string, callback: (...args: any[]) => void): void {\n\t\taddGlobalListener(event, callback);\n\t}\n\n\t/**\n\t * Alias for {@link RocksDatabase.on}, mirroring the Node `EventEmitter` API.\n\t */\n\tstatic addListener(event: string, callback: (...args: any[]) => void): void {\n\t\taddGlobalListener(event, callback);\n\t}\n\n\t/**\n\t * Removes a previously-registered process-wide event listener. The\n\t * callback identity must match the one passed to {@link RocksDatabase.on}.\n\t *\n\t * @returns `true` if a matching listener was removed.\n\t */\n\tstatic off(event: string, callback: (...args: any[]) => void): boolean {\n\t\treturn removeGlobalListener(event, callback);\n\t}\n\n\t/**\n\t * Alias for {@link RocksDatabase.off}, mirroring the Node `EventEmitter` API.\n\t */\n\tstatic removeListener(event: string, callback: (...args: any[]) => void): boolean {\n\t\treturn removeGlobalListener(event, callback);\n\t}\n\n\t/**\n\t * Returns the number of process-wide listeners registered for the given event.\n\t */\n\tstatic listenerCount(event: string): number {\n\t\treturn globalListenerCount(event);\n\t}\n\n\t/**\n\t * Emits a process-wide event. Mostly intended for tests and as a peer to\n\t * {@link RocksDatabase.on} — native code should call `emitGlobalEvent` in\n\t * `napi/global_events.h` directly rather than round-tripping through JS.\n\t *\n\t * @returns `true` if there was at least one listener.\n\t */\n\tstatic notify(event: string, ...args: any[]): boolean {\n\t\treturn globalNotify(event, args);\n\t}\n\n\t// committed\n\n\tdestroy(): void {\n\t\tthis.store.db.destroy();\n\t}\n\n\tasync drop(): Promise<void> {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.store.db.drop(resolve, reject);\n\t\t});\n\t}\n\n\tdropSync(): void {\n\t\treturn this.store.db.dropSync();\n\t}\n\n\tget encoder(): Encoder | null {\n\t\treturn this.store.encoder;\n\t}\n\n\t/**\n\t * Flushes the underlying database by performing a commit or clearing any buffered operations.\n\t *\n\t * On a read-only database this is a no-op: the options bag is still validated, but the\n\t * returned promise resolves without flushing rather than rejecting.\n\t *\n\t * @param options - Flush options; see {@link FlushOptions.allowWriteStall} before relying on\n\t * this resolving promptly under write pressure.\n\t * @return {void} Does not return a value.\n\t */\n\tflush(options?: FlushOptions): Promise<void> {\n\t\treturn new Promise((resolve, reject) => this.store.db.flush(resolve, reject, options));\n\t}\n\n\t/**\n\t * Synchronously flushes the underlying database by performing a commit or clearing any buffered operations.\n\t *\n\t * The default `allowWriteStall: false` wait is taken on the JS thread here, so it freezes the\n\t * event loop rather than parking a libuv worker — a larger blast radius than {@link flush}, not\n\t * a smaller one.\n\t *\n\t * On a read-only database this validates its options and then returns without flushing, rather\n\t * than throwing.\n\t *\n\t * @param options - Flush options; see {@link FlushOptions.allowWriteStall}.\n\t * @return {void} Does not return a value.\n\t */\n\tflushSync(options?: FlushOptions): void {\n\t\treturn this.store.db.flushSync(options);\n\t}\n\n\t/**\n\t * Returns the most recent {@link BackgroundError} observed on this database, or\n\t * `null` when none has occurred. The `'error'` event is the push counterpart;\n\t * this is the pull equivalent for on-demand checks (e.g. a health probe) and\n\t * for catching an error that fired after open but before a listener was\n\t * attached. (A background error that occurs *during* the initial open is a\n\t * narrow startup window not yet captured, addressed separately.)\n\t *\n\t * Purely historical — it is not cleared by a successful {@link RocksDatabase.resume}.\n\t * When the returned error's `writesDisabled` is `true`, writes are stopped\n\t * until recovery.\n\t *\n\t * @example\n\t * ```typescript\n\t * const err = db.getLastError();\n\t * if (err?.writesDisabled) {\n\t * // ...free disk space...\n\t * db.resume();\n\t * }\n\t * ```\n\t */\n\tgetLastError(): BackgroundError | null {\n\t\treturn this.store.db.getLastError();\n\t}\n\n\t/**\n\t * Sets or clears the last background error, mirroring the Win32\n\t * `SetLastError`/`GetLastError` pair. Pass `null` (or no argument) to **reset**\n\t * it — {@link RocksDatabase.getLastError} then returns `null` and no event\n\t * fires; this is the intended way to clear the error after handling or\n\t * recovering it (e.g. after {@link RocksDatabase.resume}). Pass an object to\n\t * set it: it is stored and the `'error'` event fires with the reconstructed\n\t * {@link BackgroundError}. `type` defaults to `'background'`.\n\t *\n\t * @example\n\t * ```typescript\n\t * db.resume();\n\t * db.setLastError(null); // recovered — clear the historical error\n\t * ```\n\t */\n\tsetLastError(error?: BackgroundErrorOptions | null): void {\n\t\tif (error == null) {\n\t\t\treturn this.store.db.setLastError(null);\n\t\t}\n\t\t// Fill the fields the BackgroundError type declares as required so a partial\n\t\t// input (e.g. just `{ message }`) never yields an error with `undefined`\n\t\t// severity/severityName/writesDisabled. severityName and writesDisabled\n\t\t// derive from severity unless the caller supplied them explicitly.\n\t\tconst severity = error.severity ?? 0;\n\t\treturn this.store.db.setLastError({\n\t\t\t...error,\n\t\t\ttype: error.type ?? 'background',\n\t\t\tseverity,\n\t\t\tseverityName: error.severityName ?? backgroundErrorSeverityName(severity),\n\t\t\twritesDisabled: error.writesDisabled ?? severity >= 2,\n\t\t});\n\t}\n\n\t/**\n\t * Attempts to recover the database from a background error by calling\n\t * RocksDB's `DB::Resume()`. When a write fails at the filesystem level (e.g. a\n\t * full disk), RocksDB stops accepting writes and this database emits an\n\t * {@link BackgroundError} via the `'error'` event. Call `resume()` after the\n\t * underlying condition has cleared — e.g. once disk space has been freed. On\n\t * success writes are accepted again; on failure (the condition has not\n\t * actually cleared) it throws and the database stays read-only. A no-op on a\n\t * healthy database.\n\t *\n\t * Runs synchronously and may briefly block, since recovery can re-flush\n\t * memtables.\n\t *\n\t * @example\n\t * ```typescript\n\t * db.on('error', (err) => {\n\t * if (err.writesDisabled) {\n\t * // ...free disk space...\n\t * db.resume();\n\t * }\n\t * });\n\t * ```\n\t */\n\tresume(): void {\n\t\treturn this.store.db.resume();\n\t}\n\n\t// flushed\n\n\t/**\n\t * Gets a RocksDB database property as an integer.\n\t *\n\t * @param propertyName - The name of the property to retrieve (e.g., 'rocksdb.num-blob-files').\n\t * @returns The property value as a number.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const blobFiles = db.getDBIntProperty('rocksdb.num-blob-files');\n\t * const numKeys = db.getDBIntProperty('rocksdb.estimate-num-keys');\n\t * ```\n\t */\n\tgetDBIntProperty(propertyName: string): number | undefined {\n\t\treturn this.store.db.getDBIntProperty(propertyName);\n\t}\n\n\t/**\n\t * Gets a RocksDB database property as a string.\n\t *\n\t * @param propertyName - The name of the property to retrieve (e.g., 'rocksdb.levelstats').\n\t * @returns The property value as a string.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const levelStats = db.getDBProperty('rocksdb.levelstats');\n\t * const stats = db.getDBProperty('rocksdb.stats');\n\t * ```\n\t */\n\tgetDBProperty(propertyName: string): string | undefined {\n\t\treturn this.store.db.getDBProperty(propertyName);\n\t}\n\n\t/**\n\t * Retrieves the estimated number of keys in the database. This is an alias\n\t * for `db.estimateCount().count`; use `estimateCount()` for range support\n\t * and a confidence indicator.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const estimated = db.getEstimatedKeyCount();\n\t * console.log(estimated);\n\t * ```\n\t */\n\tgetEstimatedKeyCount(): number {\n\t\treturn this.getDBIntProperty('rocksdb.estimate-num-keys') ?? 0;\n\t}\n\n\t/**\n\t * Estimates the number of keys in the database, or within a key range,\n\t * returning `{ count, confidence }`. Unlike `getKeysCount()`, this never\n\t * iterates: the estimate is derived from RocksDB statistics (memtable\n\t * stats plus approximate SST sizes converted through the entry density of\n\t * the SSTs overlapping the range), so its cost scales with the number of\n\t * SSTs overlapping the range rather than the number of keys — though\n\t * reading table properties for cold files can do I/O through the table\n\t * cache, and a start-only range does the work of its complement below\n\t * `start`. Accuracy improves with range size. Resolution is bounded by SST\n\t * data-block granularity, so tiny ranges may over-report or report zero for\n\t * present keys; low `confidence` is the signal. Recently deleted or\n\t * overwritten entries may be counted until compaction. An inverted range\n\t * (`start` >= `end`) returns `{ count: 0, confidence: 1 }`.\n\t *\n\t * `confidence` is a heuristic 0–1 trust indicator (1 only when exact) —\n\t * see `CountEstimate`. Estimates always reflect committed state; writes\n\t * pending in a transaction are not included.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const { count, confidence } = db.estimateCount({ start: 'a', end: 'z' });\n\t * ```\n\t */\n\testimateCount(options?: CountEstimateOptions): CountEstimate {\n\t\treturn this.store.estimateCount(options);\n\t}\n\n\t/**\n\t * Creates a `CountEstimator` for progressively refining a range count\n\t * estimate while iterating the range: report progress with\n\t * `advance(lastKey, count)` (e.g. once per page of results) and\n\t * `estimate()` returns the exact traversed count plus a calibrated\n\t * estimate of the remainder, converging toward the exact total. Call\n\t * `finish()` when traversal completes to make `estimate()` exact.\n\t *\n\t * @example\n\t * ```typescript\n\t * const estimator = db.createCountEstimator({ start: 'a', end: 'z' });\n\t * let lastKey;\n\t * let pageSize = 0;\n\t * for (const { key } of db.getRange({ start: 'a', end: 'z', limit: 25 })) {\n\t * lastKey = key;\n\t * pageSize++;\n\t * }\n\t * estimator.advance(lastKey, pageSize);\n\t * const { count, confidence } = estimator.estimate();\n\t * ```\n\t */\n\tcreateCountEstimator(options?: CountEstimatorOptions): CountEstimator {\n\t\treturn new CountEstimator(this.store, options);\n\t}\n\n\t/**\n\t * Returns the current timestamp as a monotonically increasing timestamp in\n\t * milliseconds represented as a decimal number.\n\t *\n\t * @returns The current monotonic timestamp in milliseconds.\n\t */\n\tgetMonotonicTimestamp(): number {\n\t\treturn this.store.db.getMonotonicTimestamp();\n\t}\n\n\t/**\n\t * Returns a number representing a unix timestamp of the oldest unreleased\n\t * snapshot.\n\t *\n\t * @returns The oldest snapshot timestamp.\n\t */\n\tgetOldestSnapshotTimestamp(): number {\n\t\treturn this.store.db.getOldestSnapshotTimestamp();\n\t}\n\n\t/**\n\t * Gets a RocksDB statistic.\n\t *\n\t * @param statName - The name of the statistic to retrieve.\n\t * @returns The statistic value.\n\t */\n\tgetStat(statName: string): RocksDBStat {\n\t\treturn this.store.db.getStat(statName);\n\t}\n\n\t/**\n\t * Gets the RocksDB statistics. The RocksDB ticker/histogram stats require\n\t * statistics to be enabled, but the result always includes a summarized,\n\t * aggregate set of `txnlog.*` keys (across all of this database's transaction\n\t * logs), regardless of whether statistics are enabled. For detailed per-log\n\t * statistics, including memory-map usage, use `log.getStats()` on the log\n\t * returned by {@link RocksDatabase#useLog}.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const stats = db.getStats();\n\t * stats['txnlog.totalSizeBytes']; // bytes across all transaction logs\n\t * ```\n\t */\n\tgetStats(all?: false): StatsDefault;\n\tgetStats(all: true): StatsAll;\n\tgetStats(all = false): StatsDefault | StatsAll {\n\t\treturn all ? this.store.db.getStats(true) : this.store.db.getStats(false);\n\t}\n\n\t/**\n\t * Gets or creates a buffer that can be shared across worker threads.\n\t *\n\t * @param key - The key to get or create the buffer for.\n\t * @param defaultBuffer - The default buffer to copy and use if the buffer\n\t * does not exist.\n\t * @param [options] - The options for the buffer.\n\t * @param [options.callback] - A optional callback that receives\n\t * key-specific events.\n\t * @returns An `ArrayBuffer` that is internally backed by a shared block of\n\t * memory. The buffer also has `notify()` and `cancel()` methods that can be\n\t * used to notify the specified `options.callback`.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * const buffer = db.getUserSharedBuffer('foo', new ArrayBuffer(10));\n\t */\n\tgetUserSharedBuffer(\n\t\tkey: Key,\n\t\tdefaultBuffer: ArrayBuffer,\n\t\toptions?: UserSharedBufferOptions\n\t): ArrayBufferWithNotify {\n\t\treturn this.store.getUserSharedBuffer(key, defaultBuffer, options);\n\t}\n\n\t/**\n\t * Returns whether the database has a lock for the given key.\n\t *\n\t * @param key - The key to check.\n\t * @returns `true` if the database has a lock for the given key, `false`\n\t * otherwise.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.hasLock('foo'); // false\n\t * db.tryLock('foo', () => {});\n\t * db.hasLock('foo'); // true\n\t * ```\n\t */\n\thasLock(key: Key): boolean {\n\t\treturn this.store.hasLock(key);\n\t}\n\n\tasync ifNoExists(_key: Key): Promise<void> {\n\t\t//\n\t}\n\n\t/**\n\t * Checks the process-global verification table for a fresh version match\n\t * on `key`. Returns `true` when the table currently records `version`. Use\n\t * this as a fast cache-freshness check before falling back to a full read:\n\t *\n\t * ```typescript\n\t * if (db.verifyVersion(key, cachedEntry.version)) {\n\t * return cachedEntry.value;\n\t * }\n\t * const value = db.getSync(key);\n\t * db.populateVersion(key, extractVersion(value));\n\t * ```\n\t */\n\tverifyVersion(key: Key, version: number): boolean {\n\t\treturn this.store.verifyVersion(key, version);\n\t}\n\n\t/**\n\t * Seeds the verification-table slot for `key` with `version`. Has no\n\t * effect if the slot is currently lock-tagged or if the verification\n\t * table is disabled.\n\t */\n\tpopulateVersion(key: Key, version: number): void {\n\t\tthis.store.populateVersion(key, version);\n\t}\n\n\t/**\n\t * Returns whether the database is open.\n\t *\n\t * @returns `true` if the database is open, `false` otherwise.\n\t */\n\tisOpen(): boolean {\n\t\treturn this.store.isOpen();\n\t}\n\n\t/**\n\t * Lists all transaction log names.\n\t *\n\t * @returns an array of transaction log names.\n\t */\n\tlistLogs(): string[] {\n\t\treturn this.store.listLogs();\n\t}\n\n\t/**\n\t * The name of the database.\n\t */\n\tget name(): string {\n\t\treturn this.#name;\n\t}\n\n\t/**\n\t * Whether the database is open in readonly mode.\n\t */\n\tget readOnly(): boolean {\n\t\treturn this.store.readOnly;\n\t}\n\n\t/**\n\t * Sugar method for opening a database.\n\t *\n\t * @param pathOrStore - The filesystem path to the database or a custom store.\n\t * @param options - The options for the database.\n\t * @returns A new RocksDatabase instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * ```\n\t */\n\tstatic open(pathOrStore: string | Store, options?: RocksDatabaseOptions): RocksDatabase {\n\t\treturn new RocksDatabase(pathOrStore, options).open();\n\t}\n\n\t/**\n\t * Opens the database. This function returns immediately if the database is\n\t * already open.\n\t *\n\t * @returns A new RocksDatabase instance.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = new RocksDatabase('/path/to/database');\n\t * db.open();\n\t * ```\n\t */\n\topen(): RocksDatabase {\n\t\tconst { store } = this;\n\n\t\tif (store.open()) {\n\t\t\t// already open\n\t\t\treturn this;\n\t\t}\n\n\t\tstore.db.setDefaultValueBuffer(VALUE_BUFFER);\n\t\tstore.db.setDefaultKeyBuffer(KEY_BUFFER);\n\t\tstore.db.setIteratorState(ITERATOR_STATE_BUFFER);\n\n\t\t/**\n\t\t * The encoder initialization precedence is:\n\t\t * 1. encoder.Encoder\n\t\t * 2. encoder.encode()\n\t\t * 3. encoding === `msgpack`\n\t\t * 4. encoding === `ordered-binary`\n\t\t * 5. encoder.writeKey()\n\t\t */\n\t\tlet EncoderClass: EncoderFunction | undefined = store.encoder?.Encoder;\n\t\tif (store.encoding === false) {\n\t\t\tstore.encoder = null;\n\t\t\tEncoderClass = undefined;\n\t\t} else if (typeof EncoderClass === 'function') {\n\t\t\tstore.encoder = null;\n\t\t} else if (\n\t\t\ttypeof store.encoder?.encode !== 'function' &&\n\t\t\t(!store.encoding || store.encoding === 'msgpack')\n\t\t) {\n\t\t\tstore.encoding = 'msgpack';\n\t\t\tEncoderClass = MsgpackEncoder;\n\t\t}\n\n\t\tif (EncoderClass) {\n\t\t\tconst opts: Record<string, any> = {\n\t\t\t\tcopyBuffers: true,\n\t\t\t\tfreezeData: store.freezeData,\n\t\t\t\trandomAccessStructure: store.randomAccessStructure,\n\t\t\t};\n\t\t\tconst { sharedStructuresKey } = store;\n\t\t\tif (sharedStructuresKey) {\n\t\t\t\topts.getStructures = (): any => {\n\t\t\t\t\tconst buffer = this.getBinarySync(sharedStructuresKey);\n\t\t\t\t\treturn buffer && store.decoder?.decode\n\t\t\t\t\t\t? store.decoder.decode(buffer as BufferWithDataView)\n\t\t\t\t\t\t: undefined;\n\t\t\t\t};\n\t\t\t\topts.saveStructures = (\n\t\t\t\t\tstructures: any,\n\t\t\t\t\tisCompatible: boolean | ((existingStructures: any) => boolean)\n\t\t\t\t) => {\n\t\t\t\t\treturn this.transactionSync(\n\t\t\t\t\t\t(txn: Transaction, _attempt: number) => {\n\t\t\t\t\t\t\t// note: we need to get a fresh copy of the shared structures,\n\t\t\t\t\t\t\t// so we don't want to use the transaction's getBinarySync()\n\t\t\t\t\t\t\tconst existingStructuresBuffer = this.getBinarySync(sharedStructuresKey);\n\t\t\t\t\t\t\tconst existingStructures =\n\t\t\t\t\t\t\t\texistingStructuresBuffer && store.decoder?.decode\n\t\t\t\t\t\t\t\t\t? store.decoder.decode(existingStructuresBuffer as BufferWithDataView)\n\t\t\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\t\tif (typeof isCompatible == 'function') {\n\t\t\t\t\t\t\t\tif (!isCompatible(existingStructures)) {\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else if (existingStructures && existingStructures.length !== isCompatible) {\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\ttxn.putSync(sharedStructuresKey, structures);\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{ retryOnBusy: true }\n\t\t\t\t\t);\n\t\t\t\t};\n\t\t\t}\n\t\t\tstore.encoder = new EncoderClass({ ...opts, ...store.encoder });\n\t\t\tstore.decoder = store.encoder;\n\t\t} else if (typeof store.encoder?.encode === 'function') {\n\t\t\tif (!store.decoder) {\n\t\t\t\tstore.decoder = store.encoder;\n\t\t\t}\n\t\t} else if (store.encoding === 'ordered-binary') {\n\t\t\tstore.encoder = { readKey: orderedBinary.readKey, writeKey: orderedBinary.writeKey };\n\t\t\tstore.decoder = store.encoder;\n\t\t}\n\n\t\tif (typeof store.encoder?.writeKey === 'function' && !store.encoder?.encode) {\n\t\t\t// define a fallback encode method that uses writeKey to encode values\n\t\t\tstore.encoder = {\n\t\t\t\t...store.encoder,\n\t\t\t\tencode: (value: any, _mode?: number): Buffer => {\n\t\t\t\t\tconst bytesWritten = store.writeKey(value, store.encodeBuffer, 0);\n\t\t\t\t\treturn store.encodeBuffer.subarray(0, bytesWritten);\n\t\t\t\t},\n\t\t\t\tcopyBuffers: true,\n\t\t\t};\n\t\t}\n\n\t\tif (store.encoder) {\n\t\t\tstore.encoder.name = this.#name;\n\t\t}\n\n\t\tif (store.decoder && store.decoder.needsStableBuffer !== true) {\n\t\t\tstore.decoderCopies = true;\n\t\t}\n\n\t\tif (store.decoder?.readKey && !store.decoder.decode) {\n\t\t\tstore.decoder.decode = (buffer: BufferWithDataView): any => {\n\t\t\t\tif (store.decoder?.readKey) {\n\t\t\t\t\treturn store.decoder.readKey(buffer, 0, buffer.end);\n\t\t\t\t}\n\t\t\t\treturn buffer;\n\t\t\t};\n\t\t\tstore.decoderCopies = true;\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Returns the path to the database.\n\t */\n\tget path(): string {\n\t\treturn this.store.path;\n\t}\n\n\t/**\n\t * Purges transaction logs.\n\t *\n\t * By default returns the paths of the deleted log files. Pass\n\t * `includeEntryCounts: true` to instead return, for each deleted file, its\n\t * path and the number of entries it held (`{ path, entries }`).\n\t */\n\tpurgeLogs(options: PurgeLogsOptions & { includeEntryCounts: true }): PurgedLog[];\n\tpurgeLogs(options?: PurgeLogsOptions & { includeEntryCounts?: false }): string[];\n\tpurgeLogs(options?: PurgeLogsOptions): string[] | PurgedLog[];\n\tpurgeLogs(options?: PurgeLogsOptions): string[] | PurgedLog[] {\n\t\treturn this.store.db.purgeLogs(options);\n\t}\n\n\t/**\n\t * The status of the database.\n\t */\n\tget status(): 'open' | 'closed' {\n\t\treturn this.store.isOpen() ? 'open' : 'closed';\n\t}\n\n\t/**\n\t * Executes all operations in the callback as a single transaction.\n\t *\n\t * @param callback - A async function that receives the transaction as an argument.\n\t * @returns A promise that resolves the `callback` return value.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.transaction(async (txn) => {\n\t * await txn.put('key', 'value');\n\t * });\n\t * ```\n\t */\n\tasync transaction<T>(\n\t\tcallback: TransactionCallback<T>,\n\t\toptions?: TransactionOptions\n\t): Promise<T | void> {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\tconst maxRetries = options?.maxRetries ?? 3;\n\t\tconst txn = new Transaction(this.store, options);\n\t\tlet result: T | PromiseLike<T>;\n\n\t\tthis.notify('begin-transaction');\n\n\t\tfor (let attempt = 1; attempt <= maxRetries; attempt++) {\n\t\t\ttry {\n\t\t\t\tresult = await callback(txn, attempt);\n\t\t\t} catch (callbackErr) {\n\t\t\t\treturn this.#abortTransaction(txn, callbackErr);\n\t\t\t}\n\n\t\t\tlet commitResult: typeof RETRY_NOW | void;\n\t\t\ttry {\n\t\t\t\tcommitResult = await txn.commit();\n\t\t\t} catch (commitErr) {\n\t\t\t\tif (commitErr instanceof TransactionAlreadyAbortedError) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\tcommitErr instanceof TransactionRetryableError &&\n\t\t\t\t\t(options?.retryOnBusy ?? commitErr.hasLog) &&\n\t\t\t\t\tattempt < maxRetries\n\t\t\t\t) {\n\t\t\t\t\t// retry the transaction (native reset gave it a fresh snapshot; re-run the body)\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tthis.#abandonTransaction(txn, commitErr);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (commitResult !== RETRY_NOW) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\t// coordinatedRetry: the conflict resolved, retry immediately — but only\n\t\t\t// if attempts remain. On the final attempt a RETRY_NOW must not fall\n\t\t\t// out of the loop silently (that would resolve undefined and leave the\n\t\t\t// transaction un-aborted); abandon it like an exhausted ERR_BUSY retry.\n\t\t\tif (attempt >= maxRetries) {\n\t\t\t\tthis.#abandonTransaction(\n\t\t\t\t\ttxn,\n\t\t\t\t\tnew Error(`Transaction did not commit after ${maxRetries} coordinated retries`)\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Executes all operations in the callback as a single transaction.\n\t *\n\t * @param callback - A function that receives the transaction as an\n\t * argument. If the callback return promise-like value, it is awaited\n\t * before committing the transaction. Otherwise, the callback is treated as\n\t * synchronous.\n\t * @returns The `callback` return value.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.transaction(async (txn) => {\n\t * await txn.put('key', 'value');\n\t * });\n\t * ```\n\t */\n\ttransactionSync<T>(\n\t\tcallback: TransactionCallback<T>,\n\t\toptions?: TransactionOptions\n\t): T | PromiseLike<T> | void {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\tconst maxRetries = options?.maxRetries ?? 3;\n\n\t\tconst isRetryable = (err: Error | unknown, attempt: number) => {\n\t\t\treturn (\n\t\t\t\terr instanceof TransactionRetryableError &&\n\t\t\t\t(options?.retryOnBusy ?? err.hasLog) &&\n\t\t\t\tattempt <= maxRetries\n\t\t\t);\n\t\t};\n\n\t\tconst runAttempt = (attempt: number): T | PromiseLike<T> | void => {\n\t\t\tconst txn = new Transaction(this.store, options);\n\t\t\tlet result: T | PromiseLike<T>;\n\n\t\t\ttry {\n\t\t\t\tresult = callback(txn, attempt);\n\t\t\t} catch (callbackErr) {\n\t\t\t\treturn this.#abortTransaction(txn, callbackErr);\n\t\t\t}\n\n\t\t\t// despite being 'sync', we need to support async operations\n\t\t\tif (typeof (result as PromiseLike<T>)?.then === 'function') {\n\t\t\t\treturn (result as PromiseLike<T>).then((value: T | undefined) => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttxn.commitSync();\n\t\t\t\t\t\treturn value;\n\t\t\t\t\t} catch (commitErr) {\n\t\t\t\t\t\tif (commitErr instanceof TransactionAlreadyAbortedError) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (isRetryable(commitErr, attempt)) {\n\t\t\t\t\t\t\treturn runAttempt(attempt + 1) as PromiseLike<T>;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.#abandonTransaction(txn, commitErr);\n\t\t\t\t\t}\n\t\t\t\t}) as PromiseLike<T>;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\ttxn.commitSync();\n\t\t\t\treturn result;\n\t\t\t} catch (commitErr) {\n\t\t\t\tif (commitErr instanceof TransactionAlreadyAbortedError) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (isRetryable(commitErr, attempt)) {\n\t\t\t\t\treturn runAttempt(attempt + 1);\n\t\t\t\t}\n\t\t\t\tthis.#abandonTransaction(txn, commitErr);\n\t\t\t}\n\t\t};\n\n\t\tthis.notify('begin-transaction');\n\t\treturn runAttempt(1);\n\t}\n\n\t#abortTransaction(txn: Transaction, callbackErr: Error | unknown): void {\n\t\t// either a user error or a already aborted/committed error\n\t\ttry {\n\t\t\t// in the event of a user error, we need to abort the transaction\n\t\t\ttxn.abort();\n\t\t} catch (abortErr) {\n\t\t\tif (abortErr instanceof TransactionAlreadyAbortedError) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// rethrow the user error\n\t\tthrow callbackErr;\n\t}\n\n\t#abandonTransaction(txn: Transaction, commitErr: Error | unknown): void {\n\t\ttry {\n\t\t\ttxn.abort();\n\t\t} catch (abortErr) {\n\t\t\tif (abortErr instanceof TransactionAbandonedError) {\n\t\t\t\tthrow abortErr;\n\t\t\t}\n\t\t}\n\n\t\t// rethrow the original error\n\t\tthrow commitErr;\n\t}\n\n\t/**\n\t * Attempts to acquire a lock for a given key. If the lock is available,\n\t * the function returns `true` and the optional callback is never called.\n\t * If the lock is not available, the function returns `false` and the\n\t * callback is queued until the lock is released.\n\t *\n\t * @param key - The key to lock.\n\t * @param onUnlocked - A callback to call when the lock is released.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.tryLock('foo', () => {\n\t * console.log('lock acquired');\n\t * });\n\t * ```\n\t * @returns `true` if the lock was acquired, `false` otherwise.\n\t */\n\ttryLock(key: Key, onUnlocked?: () => void): boolean {\n\t\treturn this.store.tryLock(key, onUnlocked);\n\t}\n\n\t/**\n\t * Releases the lock on the given key and calls any queued `onUnlocked`\n\t * callback handlers.\n\t *\n\t * @param key - The key to unlock.\n\t * @returns `true` if the lock was released or `false` if the lock did not\n\t * exist.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * db.tryLock('foo', () => {});\n\t * db.unlock('foo'); // returns `true`\n\t * db.unlock('foo'); // already unlocked, returns `false`\n\t * ```\n\t */\n\tunlock(key: Key): void {\n\t\treturn this.store.unlock(key);\n\t}\n\n\t/**\n\t * Excecutes a function using a thread-safe lock to ensure mutual\n\t * exclusion.\n\t *\n\t * @param callback - A callback to call when the lock is acquired.\n\t * @returns A promise that resolves when the lock is acquired.\n\t *\n\t * @example\n\t * ```typescript\n\t * const db = RocksDatabase.open('/path/to/database');\n\t * await db.withLock(async (waited) => {\n\t * console.log('lock acquired', waited);\n\t * });\n\t * ```\n\t */\n\twithLock(key: Key, callback: () => void | Promise<void>): Promise<void> | undefined {\n\t\treturn this.store.withLock(key, callback);\n\t}\n}\n","import { constants } from './load-binding.ts';\nimport { closeSync, openSync, readSync, type Stats, statSync } from 'node:fs';\n\nconst { TRANSACTION_LOG_TOKEN, TRANSACTION_LOG_ENTRY_HEADER_SIZE } = constants;\n\n// Transaction log files did not exist before this date, so any timestamp that\n// predates it indicates corruption.\nconst MIN_VALID_TIMESTAMP = Date.UTC(2026, 0, 27); // 2026-01-27\n\n// Currently only bit 0 (TRANSACTION_LOG_ENTRY_LAST_FLAG) is defined.\nconst VALID_FLAGS_MASK = 0x01;\n\ninterface LogEntry {\n\tanomalies?: string[];\n\tdata?: Buffer;\n\tflags: number;\n\tlength: number;\n\ttimestamp?: number;\n}\n\ninterface TransactionLog {\n\tanomalies: string[];\n\tentries: LogEntry[];\n\tentryAnomalyCount: number;\n\ttimestamp: number;\n\tsize: number;\n\tversion: number;\n}\n\n/**\n * Loads an entire transaction log file into memory.\n * @param path - The path to the transaction log file.\n * @returns The transaction log.\n */\nexport function parseTransactionLog(\n\tpath: string,\n\toptions: { skipData?: boolean } = {}\n): TransactionLog {\n\tlet stats: Stats;\n\ttry {\n\t\tstats = statSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n\t\t\tthrow new Error('Transaction log file does not exist');\n\t\t}\n\t\tthrow error;\n\t}\n\n\tlet { size } = stats;\n\tif (size === 0) {\n\t\tthrow new Error('Transaction log file is too small');\n\t}\n\n\tconst fileHandle = openSync(path, 'r');\n\tlet fileOffset = 0;\n\n\tconst read = (numBytes: number) => {\n\t\tconst buffer = Buffer.allocUnsafe(numBytes);\n\t\tconst bytesRead = readSync(fileHandle, buffer, 0, numBytes, fileOffset);\n\t\tfileOffset += bytesRead;\n\t\tif (bytesRead !== numBytes) {\n\t\t\t// Only hex-dump the bytes actually read, capped at 64. A corrupt length\n\t\t\t// can request a huge read; dumping the whole (largely uninitialized)\n\t\t\t// buffer can exceed V8's max string length and mask the real error.\n\t\t\tconst previewBytes = Math.min(bytesRead, 64);\n\t\t\tconst preview = buffer.subarray(0, previewBytes).toString('hex');\n\t\t\tthrow new Error(\n\t\t\t\t`Expected to read ${numBytes} bytes but only read ${bytesRead}, file offset: ${fileOffset.toString(16)}, file size: ${size}, file path: ${path}, buffer (first ${previewBytes} bytes): ${preview}`\n\t\t\t);\n\t\t}\n\t\treturn buffer;\n\t};\n\n\ttry {\n\t\t// read the file header\n\t\tconst token = read(4).readUInt32BE(0);\n\t\tif (token !== TRANSACTION_LOG_TOKEN) {\n\t\t\tthrow new Error('Invalid token');\n\t\t}\n\n\t\tconst version = read(1).readUInt8(0);\n\t\tif (version !== 1) {\n\t\t\tthrow new Error(`Unsupported transaction log file version: ${version}`);\n\t\t}\n\n\t\tconst timestamp = read(8).readDoubleBE(0);\n\t\tconst anomalies: string[] = [];\n\t\tif (!Number.isFinite(timestamp) || timestamp < MIN_VALID_TIMESTAMP) {\n\t\t\tanomalies.push(`Header timestamp ${timestamp} predates 2026-01-27 (possible corruption)`);\n\t\t}\n\n\t\t// read the entries\n\t\tconst entries: LogEntry[] = [];\n\t\tlet entryAnomalyCount = 0;\n\n\t\twhile (fileOffset < size) {\n\t\t\tconst timestamp = read(8).readDoubleBE(0);\n\t\t\tif (timestamp === 0) {\n\t\t\t\t// if we encounter zero padding, we can stop reading the entries since the next entry will start at the next 8-byte boundary, which is the same as the current file offset.\n\t\t\t\tsize = fileOffset - 8;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst length = read(4).readUInt32BE(0);\n\t\t\tconst flags = read(1).readUInt8(0);\n\t\t\t// Validate the declared length against the bytes actually remaining\n\t\t\t// before allocating. A torn/corrupt entry can claim a length far larger\n\t\t\t// than the file (e.g. a partial write that left header bytes pointing\n\t\t\t// past the data), which would otherwise drive an unbounded allocUnsafe\n\t\t\t// and OOM the process during log replay.\n\t\t\tconst remaining = size - fileOffset;\n\t\t\tif (length > remaining) {\n\t\t\t\tconst entryOffset = fileOffset - TRANSACTION_LOG_ENTRY_HEADER_SIZE;\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Corrupt entry at offset ${entryOffset.toString(16)}: declared length ${length} exceeds ${remaining} bytes remaining (file size: ${size})`\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst data = read(length);\n\n\t\t\tconst entryAnomalies: string[] = [];\n\t\t\tif (!Number.isFinite(timestamp) || timestamp < MIN_VALID_TIMESTAMP) {\n\t\t\t\tentryAnomalies.push(`timestamp ${timestamp} predates 2026-01-27 (possible corruption)`);\n\t\t\t}\n\t\t\tif ((flags & ~VALID_FLAGS_MASK) !== 0) {\n\t\t\t\tentryAnomalies.push(\n\t\t\t\t\t`flags 0x${flags.toString(16).padStart(2, '0')} contains undefined bits (expected 0x00 or 0x01)`\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst entry: LogEntry = {\n\t\t\t\ttimestamp,\n\t\t\t\tlength,\n\t\t\t\tflags,\n\t\t\t\tdata: options.skipData ? undefined : Buffer.from(data),\n\t\t\t};\n\t\t\tif (entryAnomalies.length > 0) {\n\t\t\t\tentry.anomalies = entryAnomalies;\n\t\t\t\tentryAnomalyCount += entryAnomalies.length;\n\t\t\t}\n\t\t\tentries.push(entry);\n\t\t}\n\n\t\treturn { anomalies, entries, entryAnomalyCount, timestamp, size, version };\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\terror.message = `Invalid transaction log file: ${error.message}`;\n\t\t}\n\t\tthrow error;\n\t} finally {\n\t\tcloseSync(fileHandle);\n\t}\n}\n","import {\n\tconstants,\n\ttype LogBuffer,\n\ttype TransactionEntry,\n\tTransactionLog,\n\ttype TransactionLogQueryOptions,\n} from './load-binding.ts';\n\nconst FLOAT_TO_UINT32 = new Float64Array(1);\nconst UINT32_FROM_FLOAT = new Uint32Array(FLOAT_TO_UINT32.buffer);\n\nconst { TRANSACTION_LOG_FILE_HEADER_SIZE, TRANSACTION_LOG_ENTRY_HEADER_SIZE } = constants;\n\n/**\n * Number of consecutive well-formed frames that, on their own, signal that real log data has\n * resumed after a framing break. Kept in step with `RESYNC_MIN_FRAMES` in\n * `src/binding/transaction_log/transaction_log_recovery.cpp`, which uses the same heuristic to\n * classify a break as mid-file corruption (valid entries follow) rather than a torn tail.\n */\nconst RESYNC_MIN_FRAMES = 8;\n\n/**\n * Thrown when an entry's framing is broken. `resyncPosition` is the offset where valid framing\n * resumes, when one was found: the frames after a mid-log break are intact and reachable, and\n * only the broken span between `position` and `resyncPosition` is unreadable. It is `undefined`\n * for a torn tail, where nothing follows the break.\n *\n * The iterator is left positioned at `resyncPosition` (or at end-of-log when there is none), so a\n * caller that chooses to recover the entries past the break calls `next()` again.\n */\nexport class CorruptFrameError extends RangeError {\n\t/** Sequence number of the log file the break is in. */\n\tlogId: number;\n\t/** Offset of the broken frame. */\n\tposition: number;\n\t/** Offset where valid framing resumes, or `undefined` when nothing valid follows. */\n\tresyncPosition?: number;\n\t/** Bytes between the break and the resume point that cannot be read. */\n\tunreadableBytes: number;\n\n\tconstructor(\n\t\tmessage: string,\n\t\tlogId: number,\n\t\tposition: number,\n\t\tresyncPosition: number | undefined\n\t) {\n\t\tsuper(\n\t\t\tresyncPosition === undefined\n\t\t\t\t? message\n\t\t\t\t: `${message}; valid framing resumes at ${resyncPosition.toString(16)}, ${\n\t\t\t\t\t\tresyncPosition - position\n\t\t\t\t\t} byte(s) unreadable`\n\t\t);\n\t\tthis.name = 'CorruptFrameError';\n\t\tthis.logId = logId;\n\t\tthis.position = position;\n\t\tthis.resyncPosition = resyncPosition;\n\t\tthis.unreadableBytes = resyncPosition === undefined ? 0 : resyncPosition - position;\n\t}\n}\n\n/**\n * Whether a complete, in-bounds frame begins at `pos`. The only sane bound on an entry's length is\n * the written extent: a single entry can legitimately exceed the rotation threshold (the first\n * entry written to a fresh file is always written in full). A zero timestamp is the\n * end-of-entries marker, not a frame.\n */\nfunction frameFits(dataView: DataView, pos: number, dataEnd: number): boolean {\n\tif (pos + TRANSACTION_LOG_ENTRY_HEADER_SIZE > dataEnd) {\n\t\treturn false;\n\t}\n\tif (dataView.getFloat64(pos) === 0) {\n\t\treturn false;\n\t}\n\tconst length = dataView.getUint32(pos + 8);\n\tif (length === 0) {\n\t\treturn false;\n\t}\n\treturn pos + TRANSACTION_LOG_ENTRY_HEADER_SIZE + length <= dataEnd;\n}\n\n/**\n * Finds the offset in `[from, dataEnd)` where valid log framing resumes: a run of at least\n * `RESYNC_MIN_FRAMES` well-formed frames, or a run that lands exactly on `dataEnd`. Returns\n * `undefined` when nothing resumes (a torn tail).\n *\n * `dataEnd` must be the **written extent**, not the mapped capacity. The log's memory map is\n * pre-extended well past the data, and every offset inside that zero padding reads as an\n * end-of-entries marker — so scanning against the map would both lose the exact-end signal (the\n * chain can never land on a capacity that data does not reach) and, if a zero were accepted as a\n * terminator, let a chain \"end\" anywhere in megabytes of padding. Against the written extent the\n * end is a single offset, so a chain landing on it is ~1/2^32 to be coincidence.\n *\n * The JS counterpart of `validFramingResumes()` in `transaction_log_recovery.cpp`, which answers\n * the same question at open time but keeps only the yes/no, discarding the offset.\n */\nfunction findResyncPosition(dataView: DataView, from: number, dataEnd: number): number | undefined {\n\tconst lastStart = dataEnd - TRANSACTION_LOG_ENTRY_HEADER_SIZE;\n\tfor (let start = from; start <= lastStart; start++) {\n\t\tlet pos = start;\n\t\tlet frames = 0;\n\t\twhile (frames < RESYNC_MIN_FRAMES && frameFits(dataView, pos, dataEnd)) {\n\t\t\tpos += TRANSACTION_LOG_ENTRY_HEADER_SIZE + dataView.getUint32(pos + 8);\n\t\t\tif (++frames >= RESYNC_MIN_FRAMES || pos === dataEnd) {\n\t\t\t\treturn start;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Builds the report for a broken frame, with the offset iteration should continue from. Resolves\n * the written extent here rather than per frame: `getLogFileSize` crosses into native and takes\n * the store mutex, which a healthy read must never pay.\n */\nfunction corruptFrame(\n\tmessage: string,\n\ttransactionLog: TransactionLog,\n\tdataView: DataView,\n\tlogBuffer: LogBuffer,\n\tposition: number,\n\tlimit: number,\n\tsize: number,\n\treadUncommitted: boolean\n): { error: CorruptFrameError; nextPosition: number } {\n\t// An uncommitted read's `limit` is the pre-extended map, so ask the file for its written extent;\n\t// a committed read is already bounded at the watermark.\n\tlet dataEnd = limit;\n\tif (readUncommitted) {\n\t\ttry {\n\t\t\tconst writtenExtent = transactionLog.getLogFileSize(logBuffer.logId);\n\t\t\tdataEnd = writtenExtent > 0 ? Math.min(logBuffer.length, writtenExtent) : 0;\n\t\t} catch {\n\t\t\tdataEnd = 0;\n\t\t}\n\t}\n\tconst resyncPosition = findResyncPosition(dataView, position + 1, dataEnd);\n\treturn {\n\t\terror: new CorruptFrameError(message, logBuffer.logId, position, resyncPosition),\n\t\t// With no resume point iteration is over, so land past `size` as well as the readable end:\n\t\t// a committed `size` that over-reports the mapped buffer would otherwise leave\n\t\t// `position < size`, and the next call would re-enter the loop and read off the end.\n\t\tnextPosition: resyncPosition ?? Math.max(dataEnd || limit, size, position + 1),\n\t};\n}\n\n/**\n * Returns an iterable for transaction entries within the specified range of timestamps\n * This iterable can be iterated over multiple times, and subsequent iterations will continue\n * from where the last iteration left off, allowing for iteration through the log file\n * to resume after more transactions have been committed.\n * @param start\n * @param end\n * @param exactStart - if this is true, the function will try to find the transaction that\n * exactly matches the start timestamp, and then return all subsequent transactions in the log\n * regardless of whether their timestamp is before or after the start\n */\nObject.defineProperty(TransactionLog.prototype, 'query', {\n\tvalue(\n\t\tthis: TransactionLog,\n\t\t{\n\t\t\tstart,\n\t\t\tend,\n\t\t\texactStart,\n\t\t\tstartFromLastFlushed,\n\t\t\treadUncommitted,\n\t\t\texclusiveStart,\n\t\t}: TransactionLogQueryOptions = {}\n\t): IterableIterator<TransactionEntry> {\n\t\tif (!this._lastCommittedPosition) {\n\t\t\t// if this is the first time we are querying the log, initialize the last committed position and memory map cache\n\t\t\tconst lastCommittedPosition = this._getLastCommittedPosition();\n\t\t\tthis._lastCommittedPosition = new Float64Array(lastCommittedPosition.buffer);\n\t\t\tthis._logBuffers = new Map<number, WeakRef<LogBuffer>>();\n\t\t}\n\t\tend ??= Number.MAX_VALUE;\n\n\t\tconst transactionLog = this;\n\t\tlet { logId: latestLogId, size } = loadLastPosition(this, !!readUncommitted);\n\t\tlet logId = latestLogId;\n\t\tlet position = 0;\n\t\tlet dataView: DataView;\n\t\tlet logBuffer: LogBuffer | undefined = this._currentLogBuffer; // try the current one first\n\t\tlet foundExactStart = false;\n\n\t\tif (start === undefined && !startFromLastFlushed) {\n\t\t\t// if no start timestamp is specified, start from the last committed position\n\t\t\tposition = size;\n\t\t\tif (position === 0) {\n\t\t\t\t// if the file is empty, start after the header\n\t\t\t\tposition = TRANSACTION_LOG_FILE_HEADER_SIZE;\n\t\t\t}\n\t\t\tstart = 0;\n\t\t} else {\n\t\t\tif (startFromLastFlushed) {\n\t\t\t\t// read from the last flushed position\n\t\t\t\tFLOAT_TO_UINT32[0] = this._getLastFlushed();\n\t\t\t\tif (FLOAT_TO_UINT32[0] === 0) {\n\t\t\t\t\t// no flushes have ever occurred, go to the beginning (which is actually after the file header)\n\t\t\t\t\tFLOAT_TO_UINT32[0] = this._findPosition(0);\n\t\t\t\t}\n\t\t\t\tstart ??= 0; // if no start timestamp is specified, include all\n\t\t\t} else {\n\t\t\t\t// otherwise, find the log file that contains the start timestamp, and find the position within that file\n\t\t\t\tFLOAT_TO_UINT32[0] = this._findPosition(start!);\n\t\t\t}\n\t\t\t// extract the log file ID from the 64-bit float returned by _findPosition, which is stored in the high 32 bits of the float\n\t\t\tlogId = UINT32_FROM_FLOAT[1];\n\t\t\t// and position from the low 32 bits of the float\n\t\t\tposition = UINT32_FROM_FLOAT[0];\n\t\t\tif (position === 0) {\n\t\t\t\t// if the file is empty, start after the header\n\t\t\t\tposition = TRANSACTION_LOG_FILE_HEADER_SIZE;\n\t\t\t}\n\t\t}\n\n\t\tif (logBuffer === undefined || logBuffer.logId !== logId) {\n\t\t\t// if the current log buffer is not the one we want, load the memory map\n\t\t\tlogBuffer = getLogMemoryMap(this, logId);\n\n\t\t\t// if this is the latest, cache for easy access, unless...\n\t\t\t// if we are reading uncommitted, we might be a log file ahead of the committed transaction\n\t\t\t// also, it is pointless to cache the latest log file in a memory map on Windows, because it is not growable\n\t\t\tif (logBuffer && latestLogId === logId && !readUncommitted) {\n\t\t\t\tthis._currentLogBuffer = logBuffer;\n\t\t\t}\n\n\t\t\tif (logBuffer === undefined) {\n\t\t\t\t// create a fake log buffer if we don't have any log buffer yet\n\t\t\t\tlogBuffer = Buffer.alloc(0) as unknown as LogBuffer;\n\t\t\t\tlogBuffer.logId = 0;\n\t\t\t\tlogBuffer.size = 0;\n\t\t\t\tlogBuffer.dataView = new DataView(logBuffer.buffer);\n\t\t\t\t// the outer size variable was set from loadLastPosition() above, but if we\n\t\t\t\t// couldn't acquire a memory map for that logId (e.g. the committed-position\n\t\t\t\t// references a logId that doesn't exist on disk — purged, never created, or\n\t\t\t\t// torn write of the position word), reading at any non-zero size would read\n\t\t\t\t// past the empty buffer. force size to match the empty buffer; the iterator's\n\t\t\t\t// position-vs-size logic then routes through the existing advance-to-next-log\n\t\t\t\t// path, which correctly returns done when no log file can be mapped.\n\t\t\t\tsize = 0;\n\t\t\t}\n\t\t}\n\n\t\tdataView = logBuffer.dataView;\n\n\t\tif (latestLogId !== logId) {\n\t\t\tsize = logBuffer.size;\n\t\t\tif (size === undefined) {\n\t\t\t\tsize = logBuffer.size = this.getLogFileSize(logId);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\t[Symbol.iterator](): IterableIterator<TransactionEntry> {\n\t\t\t\treturn this;\n\t\t\t},\n\t\t\tnext() {\n\t\t\t\tlet timestamp: number;\n\t\t\t\tif (position >= size) {\n\t\t\t\t\t// our position is beyond the size limit, get the updated\n\t\t\t\t\t// size in case we can keep reading further from the same block\n\t\t\t\t\tconst { logId: latestLogId, size: latestSize } = loadLastPosition(\n\t\t\t\t\t\ttransactionLog,\n\t\t\t\t\t\t!!readUncommitted\n\t\t\t\t\t);\n\t\t\t\t\tsize = latestSize;\n\t\t\t\t\tif (latestLogId > logBuffer!.logId) {\n\t\t\t\t\t\t// if it is not the latest log, get the file size\n\t\t\t\t\t\tsize =\n\t\t\t\t\t\t\tlogBuffer!.size ??\n\t\t\t\t\t\t\t(logBuffer!.size = transactionLog.getLogFileSize(logBuffer!.logId));\n\t\t\t\t\t\tif (position >= size) {\n\t\t\t\t\t\t\t// we can't read any further in this block, go to the next block\n\t\t\t\t\t\t\tconst nextLogBuffer = getLogMemoryMap(transactionLog, logBuffer!.logId + 1)!;\n\t\t\t\t\t\t\tif (nextLogBuffer) {\n\t\t\t\t\t\t\t\tdataView = nextLogBuffer.dataView;\n\t\t\t\t\t\t\t\tlogBuffer = nextLogBuffer;\n\t\t\t\t\t\t\t\tif (latestLogId > logBuffer!.logId) {\n\t\t\t\t\t\t\t\t\t// it is non-current log file, we can safely use or cache the size\n\t\t\t\t\t\t\t\t\tsize =\n\t\t\t\t\t\t\t\t\t\tlogBuffer!.size ??\n\t\t\t\t\t\t\t\t\t\t(logBuffer!.size = transactionLog.getLogFileSize(logBuffer!.logId));\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tsize = latestSize; // use the latest position from loadLastPosition\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tposition = TRANSACTION_LOG_FILE_HEADER_SIZE;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\twhile (position < size) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\ttimestamp = dataView.getFloat64(position);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t(error as Error).message += ` at position ${position.toString(16)} of log ${\n\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t} (size=${size}, log buffer length=${logBuffer!.length})`;\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t\tif (!timestamp) {\n\t\t\t\t\t\t// we have gone beyond the last transaction and reached the end\n\t\t\t\t\t\treturn { done: true, value: undefined };\n\t\t\t\t\t}\n\n\t\t\t\t\t// Corruption bound: a committed read can't legitimately extend past\n\t\t\t\t\t// the committed `size` (a true entry boundary); an uncommitted read is\n\t\t\t\t\t// bounded only by the physically mapped buffer. In both cases the bound\n\t\t\t\t\t// is also clamped to `logBuffer.length` — if committed `size` over-reports\n\t\t\t\t\t// the mapped buffer (e.g. a truncated/torn file), an unclamped `size`\n\t\t\t\t\t// would let `position` advance past the buffer and `subarray` silently\n\t\t\t\t\t// return a truncated frame instead of throwing. A torn/corrupt entry\n\t\t\t\t\t// can declare a length far past this bound — without the checks below,\n\t\t\t\t\t// `position` runs past the buffer, `subarray` hands back a misframed\n\t\t\t\t\t// (garbage) transaction, and the advance-to-next-log path can\n\t\t\t\t\t// dereference an undefined buffer. Fail loudly with a bounded error.\n\t\t\t\t\t// The throw leaves `position` at the resume point, so a broken frame ends the\n\t\t\t\t\t// entry rather than the rest of the log (HarperFast/harper#2016, #2063).\n\t\t\t\t\tconst limit = readUncommitted ? logBuffer!.length : Math.min(size, logBuffer!.length);\n\t\t\t\t\tif (position + TRANSACTION_LOG_ENTRY_HEADER_SIZE > limit) {\n\t\t\t\t\t\tconst broken = corruptFrame(\n\t\t\t\t\t\t\t`Corrupt transaction log: truncated entry header at position ${position.toString(16)} of log ${\n\t\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t\t} (available=${limit - position})`,\n\t\t\t\t\t\t\ttransactionLog,\n\t\t\t\t\t\t\tdataView,\n\t\t\t\t\t\t\tlogBuffer!,\n\t\t\t\t\t\t\tposition,\n\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\tsize,\n\t\t\t\t\t\t\t!!readUncommitted\n\t\t\t\t\t\t);\n\t\t\t\t\t\tposition = broken.nextPosition;\n\t\t\t\t\t\tthrow broken.error;\n\t\t\t\t\t}\n\t\t\t\t\tconst length = dataView.getUint32(position + 8);\n\t\t\t\t\tif (length === 0 || position + TRANSACTION_LOG_ENTRY_HEADER_SIZE + length > limit) {\n\t\t\t\t\t\tconst broken = corruptFrame(\n\t\t\t\t\t\t\tlength === 0\n\t\t\t\t\t\t\t\t? `Corrupt transaction log entry at position ${position.toString(16)} of log ${\n\t\t\t\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t\t\t\t}: zero-length entry`\n\t\t\t\t\t\t\t\t: `Corrupt transaction log entry at position ${position.toString(16)} of log ${\n\t\t\t\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t\t\t\t}: declared length ${length} overruns the log (limit=${limit})`,\n\t\t\t\t\t\t\ttransactionLog,\n\t\t\t\t\t\t\tdataView,\n\t\t\t\t\t\t\tlogBuffer!,\n\t\t\t\t\t\t\tposition,\n\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\tsize,\n\t\t\t\t\t\t\t!!readUncommitted\n\t\t\t\t\t\t);\n\t\t\t\t\t\tposition = broken.nextPosition;\n\t\t\t\t\t\tthrow broken.error;\n\t\t\t\t\t}\n\t\t\t\t\tposition += TRANSACTION_LOG_ENTRY_HEADER_SIZE;\n\t\t\t\t\tlet matchesRange: boolean;\n\t\t\t\t\tif (foundExactStart) {\n\t\t\t\t\t\t// already found the exact start, only need to match on remaining conditions\n\t\t\t\t\t\tmatchesRange = (!exclusiveStart || timestamp !== start) && timestamp < end;\n\t\t\t\t\t} else if (exactStart) {\n\t\t\t\t\t\t// in exact start mode, we are look for the exact identifying timestamp of the first transaction\n\t\t\t\t\t\tif (timestamp === start) {\n\t\t\t\t\t\t\tmatchesRange = !exclusiveStart;\n\t\t\t\t\t\t\t// after finding this transaction, match all remaining (but still respecting end and exclusiveStart\n\t\t\t\t\t\t\tfoundExactStart = true;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmatchesRange = false;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// no exact start, so just match on conditions\n\t\t\t\t\t\tmatchesRange =\n\t\t\t\t\t\t\t(exclusiveStart ? timestamp > start! : timestamp >= start!) && timestamp < end;\n\t\t\t\t\t}\n\t\t\t\t\tconst entryStart = position;\n\t\t\t\t\tposition += length;\n\t\t\t\t\tif (matchesRange) {\n\t\t\t\t\t\t// fits in the same block, just subarray the data out\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tdone: false,\n\t\t\t\t\t\t\tvalue: {\n\t\t\t\t\t\t\t\ttimestamp,\n\t\t\t\t\t\t\t\tendTxn: Boolean(logBuffer![entryStart - 1] & 1),\n\t\t\t\t\t\t\t\tdata: logBuffer!.subarray(entryStart, position),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tif (position >= size) {\n\t\t\t\t\t\t// move to the next log file\n\t\t\t\t\t\tconst { logId: latestLogId, size: latestSize } = loadLastPosition(\n\t\t\t\t\t\t\ttransactionLog,\n\t\t\t\t\t\t\t!!readUncommitted\n\t\t\t\t\t\t);\n\t\t\t\t\t\tsize = latestSize;\n\t\t\t\t\t\tif (latestLogId > logBuffer!.logId) {\n\t\t\t\t\t\t\tconst nextLogBuffer = getLogMemoryMap(transactionLog, logBuffer!.logId + 1);\n\t\t\t\t\t\t\tif (!nextLogBuffer) {\n\t\t\t\t\t\t\t\t// the next log file can't be mapped (purged, mid-rotation,\n\t\t\t\t\t\t\t\t// 0-byte at mmap time, FS race); stop cleanly rather than\n\t\t\t\t\t\t\t\t// dereferencing an undefined buffer\n\t\t\t\t\t\t\t\treturn { done: true, value: undefined };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tlogBuffer = nextLogBuffer;\n\t\t\t\t\t\t\tdataView = logBuffer.dataView;\n\t\t\t\t\t\t\tsize = logBuffer.size;\n\t\t\t\t\t\t\tif (size == undefined) {\n\t\t\t\t\t\t\t\tsize = transactionLog.getLogFileSize(logBuffer.logId);\n\t\t\t\t\t\t\t\tif (!readUncommitted) {\n\t\t\t\t\t\t\t\t\tlogBuffer.size = size;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tposition = TRANSACTION_LOG_FILE_HEADER_SIZE;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn { done: true, value: undefined };\n\t\t\t},\n\t\t};\n\t},\n});\n\nfunction getLogMemoryMap(transactionLog: TransactionLog, logId: number): LogBuffer | undefined {\n\tif (logId <= 0) {\n\t\treturn;\n\t}\n\tlet logBuffer = transactionLog._logBuffers!.get(logId)?.deref();\n\tif (logBuffer) {\n\t\t// if we have a cached buffer, return it\n\t\treturn logBuffer;\n\t}\n\ttry {\n\t\tlogBuffer = transactionLog._getMemoryMapOfFile(logId);\n\t} catch (error) {\n\t\t(error as Error).message += ` (log file ID: ${logId})`;\n\t\tthrow error;\n\t}\n\tif (!logBuffer) {\n\t\treturn;\n\t}\n\tlogBuffer.logId = logId;\n\tlogBuffer.dataView = new DataView(logBuffer.buffer);\n\ttransactionLog._logBuffers!.set(logId, new WeakRef(logBuffer)); // add to cache\n\tlet maxMisses = 3;\n\tfor (const [logId, reference] of transactionLog._logBuffers!) {\n\t\t// clear out any references that have been collected\n\t\tif (reference.deref() === undefined) {\n\t\t\ttransactionLog._logBuffers!.delete(logId);\n\t\t} else if (--maxMisses === 0) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn logBuffer;\n}\n\nfunction loadLastPosition(\n\ttransactionLog: TransactionLog,\n\treadUncommitted: boolean\n): { logId: number; size: number } {\n\t// atomically copy the full 64-bit last committed position word to a local variable so we can read it without memory tearing\n\tFLOAT_TO_UINT32[0] = transactionLog._lastCommittedPosition![0];\n\tlet logId = UINT32_FROM_FLOAT[1];\n\tlet size = 0;\n\n\tif (readUncommitted) {\n\t\t// if we are reading uncommitted transactions, we need to read the entire log file to find the latest position\n\t\tlet nextSize = 0;\n\t\tlet nextLogId = logId || 1;\n\t\twhile (true) {\n\t\t\tnextSize = transactionLog.getLogFileSize(nextLogId);\n\t\t\tif (nextSize === 0) {\n\t\t\t\t// if the size is zero, there is no next log file, we are done\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tsize = nextSize;\n\t\t\t\tlogId = nextLogId++;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// otherwise, just use the last committed position, which indicates the latest committed transaction in the log\n\t\tsize = UINT32_FROM_FLOAT[0];\n\t}\n\treturn { logId, size };\n}\n","import { version } from './load-binding.ts';\n\nexport {\n\tbackups,\n\ttype BackupInfo,\n\ttype BackupOptions,\n\ttype RestoreMode,\n\ttype RestoreOptions,\n} from './backup.ts';\nexport type { BackupStreamOptions } from './backup-stream.ts';\nexport {\n\tRocksDatabase,\n\ttype RocksDatabaseOptions,\n\ttype RocksDBStat,\n\ttype RocksDBStats,\n} from './database.ts';\nexport { CountEstimator, type CountEstimatorOptions } from './count-estimator.ts';\nexport { DBIterator } from './dbi-iterator.ts';\nexport { DBI, type CountEstimate, type CountEstimateOptions, type IteratorOptions } from './dbi.ts';\nexport type { Key } from './encoding.ts';\nexport type * from './stats.ts';\nexport {\n\tBackgroundError,\n\ttype BackgroundErrorOptions,\n\tconstants,\n\tcoolTransactionLogs,\n\tcurrentThreadId,\n\tfileLockRelease,\n\ttryFileLock,\n\tregistryStatus,\n\tstats,\n\tshutdown,\n\tsupportedCompression,\n\tTransactionLog,\n\ttype FlushOptions,\n\ttype TransactionEntry,\n\ttype TransactionLogPosition,\n\ttype TransactionLogStats,\n} from './load-binding.ts';\nexport * from './parse-transaction-log.ts';\nexport {\n\tvalidateTransactionLogStore,\n\ttype TransactionLogFileValidation,\n\ttype TransactionLogStoreValidation,\n\ttype ValidateTransactionLogStoreOptions,\n} from './validate-transaction-log.ts';\nexport {\n\ttype CompressionAlgorithm,\n\ttype CompressionInfo,\n\ttype CompressionOption,\n\ttype LogOptions,\n\tStore,\n\ttype StoreContext,\n\ttype StoreGetOptions,\n\ttype StoreIteratorOptions,\n\ttype StorePutOptions,\n\ttype StoreRangeOptions,\n\ttype StoreRemoveOptions,\n} from './store.ts';\nexport { Transaction } from './transaction.ts';\n\nimport './transaction-log-reader.ts'; // installs TransactionLog.prototype.query\nexport { CorruptFrameError } from './transaction-log-reader.ts';\n\nexport const versions: { rocksdb: string; 'rocksdb-js': string } = {\n\trocksdb: version,\n\t'rocksdb-js': 'ROCKSDB_JS_VERSION',\n};\n"],"mappings":"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"}
|