@harperfast/rocksdb-js 0.1.1 → 0.1.2
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 +12 -0
- package/dist/index.cjs +12 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -1
- package/dist/index.d.mts +6 -1
- package/dist/index.mjs +12 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +13 -13
package/README.md
CHANGED
|
@@ -108,6 +108,18 @@ There's also a static `open()` method for convenience that performs the same thi
|
|
|
108
108
|
const db = RocksDatabase.open('path/to/db');
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
+
### `db.name: string`
|
|
112
|
+
|
|
113
|
+
Returns the database column family's name.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
const db = new RocksDatabase('path/to/db');
|
|
117
|
+
console.log(db.name); // 'default'
|
|
118
|
+
|
|
119
|
+
const db2 = new RocksDatabase('path/to/db', { name: 'users' });
|
|
120
|
+
console.log(db.name); // 'users'
|
|
121
|
+
```
|
|
122
|
+
|
|
111
123
|
## Data Operations
|
|
112
124
|
|
|
113
125
|
### `db.clear(options?): Promise<number>`
|
package/dist/index.cjs
CHANGED
|
@@ -1079,10 +1079,15 @@ var Transaction = class extends DBI {
|
|
|
1079
1079
|
* ```
|
|
1080
1080
|
*/
|
|
1081
1081
|
var RocksDatabase = class RocksDatabase extends DBI {
|
|
1082
|
+
/**
|
|
1083
|
+
* The name of the database.
|
|
1084
|
+
*/
|
|
1085
|
+
#name;
|
|
1082
1086
|
constructor(pathOrStore, options) {
|
|
1083
1087
|
if (typeof pathOrStore === "string") super(new Store(pathOrStore, options));
|
|
1084
1088
|
else if (pathOrStore instanceof Store) super(pathOrStore);
|
|
1085
1089
|
else throw new TypeError("Invalid database path or store");
|
|
1090
|
+
this.#name = options?.name ?? "default";
|
|
1086
1091
|
}
|
|
1087
1092
|
/**
|
|
1088
1093
|
* Removes all data from the database asynchronously.
|
|
@@ -1281,6 +1286,12 @@ var RocksDatabase = class RocksDatabase extends DBI {
|
|
|
1281
1286
|
return this.store.listLogs();
|
|
1282
1287
|
}
|
|
1283
1288
|
/**
|
|
1289
|
+
* The name of the database.
|
|
1290
|
+
*/
|
|
1291
|
+
get name() {
|
|
1292
|
+
return this.#name;
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1284
1295
|
* Sugar method for opening a database.
|
|
1285
1296
|
*
|
|
1286
1297
|
* @param pathOrStore - The filesystem path to the database or a custom store.
|
|
@@ -1787,7 +1798,7 @@ function loadLastPosition(transactionLog, readUncommitted) {
|
|
|
1787
1798
|
//#region src/index.ts
|
|
1788
1799
|
const versions = {
|
|
1789
1800
|
rocksdb: version,
|
|
1790
|
-
"rocksdb-js": "0.1.
|
|
1801
|
+
"rocksdb-js": "0.1.2"
|
|
1791
1802
|
};
|
|
1792
1803
|
|
|
1793
1804
|
//#endregion
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["#context","#includeValues","orderedBinary","ExtendedIterable","#txn","MsgpackEncoder","orderedBinary"],"sources":["../src/load-binding.ts","../src/util.ts","../src/dbi.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 { 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';\nimport type { IteratorOptions, RangeOptions } from './dbi.js';\nimport type { BufferWithDataView, Key } from './encoding.js';\nimport type { Context } from './store.js';\n\nexport type TransactionOptions = {\n\t/**\n\t * Whether to disable snapshots.\n\t *\n\t * @default false\n\t */\n\tdisableSnapshot?: boolean;\n};\n\nexport type NativeTransaction = {\n\tid: number;\n\tnew(context: NativeDatabase, options?: TransactionOptions): NativeTransaction;\n\tabort(): void;\n\tcommit(resolve: () => 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) => void,\n\t\treject: (err: Error) => void\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 & { dataView: DataView; logId: number; size: number };\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 = { timestamp: number; data: Buffer; endTxn: boolean };\n\nexport type TransactionLog = {\n\tnew(name: string): TransactionLog;\n\taddEntry(data: Buffer | Uint8Array, txnId?: number): void;\n\tquery(options?: TransactionLogQueryOptions): IterableIterator<TransactionEntry>;\n\t_getLastFlushed(): number;\n\t_getLastCommittedPosition(): Buffer;\n\t_getMemoryMapOfFile(sequenceId: number): LogBuffer | undefined;\n\tgetLogFileSize(sequenceId?: number): number;\n\t_getLastCommittedPosition(): Buffer;\n\t_findPosition(timestamp: number): number;\n\t_lastCommittedPosition: Float64Array;\n\t_logBuffers: Map<number, WeakRef<LogBuffer>>;\n\t_currentLogBuffer: LogBuffer;\n};\n\nexport declare class NativeIteratorCls<T> implements Iterator<T> {\n\tconstructor(context: Context, options: IteratorOptions);\n\tnext(): IteratorResult<T>;\n\treturn(): IteratorResult<T>;\n\tthrow(): IteratorResult<T>;\n}\n\nexport type NativeDatabaseMode = 'optimistic' | 'pessimistic';\n\nexport type NativeDatabaseOptions = {\n\tdisableWAL?: boolean;\n\tmode?: NativeDatabaseMode;\n\tname?: string;\n\tnoBlockCache?: boolean;\n\tparallelismThreads?: number;\n\ttransactionLogMaxAgeThreshold?: number;\n\ttransactionLogMaxSize?: number;\n\ttransactionLogRetentionMs?: number;\n\ttransactionLogsPath?: string;\n};\n\ntype ResolveCallback<T> = (value: T) => void;\ntype RejectCallback = (err: Error) => void;\n\nexport type UserSharedBufferCallback = () => void;\n\nexport type PurgeLogsOptions = { destroy?: boolean; name?: string };\n\nexport type NativeDatabase = {\n\tnew(): NativeDatabase;\n\taddListener(event: string, callback: (...args: any[]) => void): void;\n\tclear(resolve: ResolveCallback<void>, reject: RejectCallback): void;\n\tclearSync(): void;\n\tclose(): 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>,\n\t\treject: RejectCallback,\n\t\ttxnId?: number\n\t): number;\n\tgetCount(options?: RangeOptions, txnId?: number): number;\n\tgetDBIntProperty(propertyName: string): number;\n\tgetDBProperty(propertyName: string): string;\n\tgetMonotonicTimestamp(): number;\n\tgetOldestSnapshotTimestamp(): number;\n\tgetSync(keyLengthOrKeyBuffer: number | Buffer, flags: number, txnId?: number): 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\tpurgeLogs(options?: PurgeLogsOptions): string[];\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\ttryLock(key: BufferWithDataView, callback?: () => void): boolean;\n\tunlock(key: BufferWithDataView): void;\n\tuseLog(name: string): TransactionLog;\n\twithLock(key: BufferWithDataView, callback: () => void | Promise<void>): Promise<void>;\n};\n\nexport type RocksDatabaseConfig = { blockCacheSize?: number };\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\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 = (!report?.header || !report.header.glibcVersionRuntime) &&\n\t\t\t\t\tArray.isArray(report?.sharedObjects) && report.sharedObjects.some(obj =>\n\t\t\t\t\t\tobj.includes('libc.musl-') || obj.includes('ld-musl-')\n\t\t\t\t\t);\n\t\t\t}\n\t\t\tisMusl = isMusl || execSync('ldd --version', { encoding: 'utf8' }).includes('musl');\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\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 constants: {\n\tTRANSACTION_LOG_TOKEN: number;\n\tTRANSACTION_LOG_FILE_HEADER_SIZE: number;\n\tTRANSACTION_LOG_ENTRY_HEADER_SIZE: number;\n\tONLY_IF_IN_MEMORY_CACHE_FLAG: number;\n\tNOT_IN_MEMORY_CACHE_FLAG: number;\n\tALWAYS_CREATE_NEW_BUFFER_FLAG: number;\n} = binding.constants;\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 version: string = binding.version;\nexport const shutdown: () => void = binding.shutdown;\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 type { NativeTransaction, TransactionLog } from './load-binding.js';\nimport type { Context, GetOptions, PutOptions, Store } 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// limit?: 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: Context;\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(() => this.getBinaryFast(key, options), result => {\n\t\t\t\tif (result === undefined) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tif (options?.skipDecode) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\treturn this.store.decodeValue(result as BufferWithDataView);\n\t\t\t});\n\t\t}\n\n\t\treturn when(\n\t\t\t() => this.getBinary(key, options),\n\t\t\tresult =>\n\t\t\t\tresult === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: (this.store.encoding === 'binary' || !this.store.decoder || options?.skipDecode)\n\t\t\t\t\t? result\n\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 | 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, this.store.getTxnId(options));\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 | 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 | 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, this.store.getTxnId(options));\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 | 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.getRange(this.#context, { ...options, values: false }).map(item => item.key);\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.getCount(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 ? undefined : 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 ? this.store.decodeValue(result as BufferWithDataView) : undefined;\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 as DBITransactional);\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 as DBITransactional);\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: () => 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","import type { IteratorOptions } from './dbi.js';\nimport type { BufferWithDataView, Key } from './encoding.js';\nimport type { Store } from './store.js';\n\nexport interface DBIteratorValue<T> {\n\tkey: Key;\n\tvalue: T;\n}\n\n/**\n * Wraps an iterator, namely the `NativeIterator` class, and decodes the key\n * and value.\n */\nexport class DBIterator<T> implements Iterator<DBIteratorValue<T>> {\n\titerator: Iterator<DBIteratorValue<T>>;\n\tstore: Store;\n\t#includeValues: boolean;\n\n\tconstructor(iterator: Iterator<DBIteratorValue<T>>, store: Store, options?: IteratorOptions & T) {\n\t\tthis.iterator = iterator;\n\t\tthis.store = store;\n\t\tthis.#includeValues = options?.values ?? true;\n\t}\n\n\t[Symbol.iterator](): Iterator<DBIteratorValue<T>> {\n\t\treturn this;\n\t}\n\n\tnext(...[_value]: [] | [any]): IteratorResult<DBIteratorValue<T>> {\n\t\tconst result = this.iterator.next();\n\t\tif (result.done) {\n\t\t\treturn result;\n\t\t}\n\n\t\tconst value: Partial<DBIteratorValue<T>> = {};\n\t\tvalue.key = this.store.decodeKey(result.value.key as Buffer);\n\t\tif (this.#includeValues) {\n\t\t\tvalue.value = this.store.decodeValue(result.value.value as BufferWithDataView);\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\tif (this.iterator.return) {\n\t\t\treturn this.iterator.return(value);\n\t\t}\n\t\treturn { done: true, value };\n\t}\n\n\tthrow(err: unknown): IteratorResult<DBIteratorValue<T>, any> {\n\t\tif (this.iterator.throw) {\n\t\t\treturn this.iterator.throw(err);\n\t\t}\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\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 { ExtendedIterable } from '@harperfast/extended-iterable';\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\ttype TransactionLog,\n\ttype UserSharedBufferCallback,\n} from './load-binding.js';\nimport { parseDuration } from './util.js';\n\nconst { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG } =\n\tconstants;\nconst KEY_BUFFER_SIZE = 4096;\nexport const KEY_BUFFER: BufferWithDataView = createFixedBuffer(KEY_BUFFER_SIZE);\nexport const VALUE_BUFFER: BufferWithDataView = createFixedBuffer(64 * 1024);\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 Context = NativeDatabase | NativeTransaction;\n\n/**\n * Options for the `Store` class.\n */\nexport interface StoreOptions\n\textends Omit<NativeDatabaseOptions, 'mode' | 'transactionLogRetentionMs'>\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// readOnly?: 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 & { cancel: () => void; notify: () => void };\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 * This store should not be shared between `RocksDatabase` instances.\n */\nexport class Store {\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 * Whether to disable the write ahead log.\n\t */\n\tdisableWAL: 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 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.\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 * 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 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 * 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.decoder = options?.decoder ?? null;\n\t\tthis.disableWAL = options?.disableWAL ?? 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.name = options?.name ?? 'default';\n\t\tthis.noBlockCache = options?.noBlockCache;\n\t\tthis.parallelismThreads = options?.parallelismThreads ?? 1;\n\t\tthis.path = path;\n\t\tthis.pessimistic = options?.pessimistic ?? false;\n\t\tthis.randomAccessStructure = options?.randomAccessStructure ?? false;\n\t\tthis.readKey = readKey;\n\t\tthis.sharedStructuresKey = options?.sharedStructuresKey;\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.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 * 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: NativeDatabase | NativeTransaction,\n\t\tkey: Key,\n\t\talwaysCreateNewBuffer: boolean = false,\n\t\ttxnId?: number\n\t): any | undefined {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\tlet flags = 0;\n\t\tif (alwaysCreateNewBuffer) { // 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\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(keyParam, flags | ONLY_IF_IN_MEMORY_CACHE_FLAG, txnId);\n\t\tif (typeof result === 'number') { // 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);\n\t\t\t\t});\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: NativeDatabase | NativeTransaction, options?: RangeOptions): 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\tgetRange(\n\t\tcontext: NativeDatabase | NativeTransaction,\n\t\toptions?: IteratorOptions & DBITransactional\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\toptions = { ...options };\n\n\t\tconst unencodedStartKey = options.key ?? options.start;\n\n\t\tif (unencodedStartKey !== undefined) {\n\t\t\tconst start = this.encodeKey(unencodedStartKey);\n\t\t\toptions.start = Buffer.from(start.subarray(start.start, start.end));\n\t\t}\n\n\t\tif (options.key !== undefined) {\n\t\t\toptions.end = options.start;\n\t\t\toptions.inclusiveEnd = true;\n\t\t} else if (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\tif (options.reverse) {\n\t\t\t// reverse the start and end keys\n\t\t\tconst start = options.start;\n\t\t\toptions.start = options.end;\n\t\t\toptions.end = start;\n\n\t\t\t// reverse the exclusive start and end flags\n\t\t\toptions.exclusiveStart = options.exclusiveStart ?? true;\n\t\t\toptions.inclusiveEnd = options.inclusiveEnd ?? true;\n\t\t}\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, options) as Iterator<DBIteratorValue<any>>,\n\t\t\t\tthis,\n\t\t\t\toptions\n\t\t\t)\n\t\t);\n\t}\n\n\tgetSync(\n\t\tcontext: NativeDatabase | NativeTransaction,\n\t\tkey: Key,\n\t\talwaysCreateNewBuffer: boolean = false,\n\t\toptions?: GetOptions & DBITransactional\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\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(keyParam, flags, this.getTxnId(options));\n\t\tif (typeof result === 'number') { // 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 ((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\tthis.db.open(this.path, {\n\t\t\tdisableWAL: this.disableWAL,\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\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});\n\n\t\treturn false;\n\t}\n\n\tputSync(\n\t\tcontext: NativeDatabase | NativeTransaction,\n\t\tkey: Key,\n\t\tvalue: any,\n\t\toptions?: PutOptions & DBITransactional\n\t): 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(\n\t\tcontext: NativeDatabase | NativeTransaction,\n\t\tkey: Key,\n\t\toptions?: DBITransactional | undefined\n\t): 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: NativeDatabase | NativeTransaction, 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\treturn context.useLog(String(name));\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 * 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 { NativeTransaction, type TransactionOptions } from './load-binding.js';\nimport { Store } from './store.js';\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?: TransactionOptions) {\n\t\tconst txn = new NativeTransaction(store.db, options);\n\t\tsuper(store, txn);\n\t\tthis.#txn = txn;\n\t}\n\n\t/**\n\t * Abort the transaction.\n\t */\n\tabort(): void {\n\t\tthis.#txn.abort();\n\t}\n\n\t/**\n\t * Commit the transaction.\n\t */\n\tasync commit(): Promise<void> {\n\t\ttry {\n\t\t\tawait new Promise<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} 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} 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 * 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 { Encoder as MsgpackEncoder } from 'msgpackr';\nimport * as orderedBinary from 'ordered-binary';\nimport { DBI, type DBITransactional } from './dbi.js';\nimport type { BufferWithDataView, Encoder, EncoderFunction, Key } from './encoding.js';\nimport {\n\tconfig,\n\ttype PurgeLogsOptions,\n\ttype RocksDatabaseConfig,\n\ttype TransactionOptions,\n} from './load-binding.js';\nimport {\n\ttype ArrayBufferWithNotify,\n\tKEY_BUFFER,\n\tStore,\n\ttype StoreOptions,\n\ttype UserSharedBufferOptions,\n\tVALUE_BUFFER,\n} from './store.js';\nimport { Transaction } from './transaction.js';\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\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\tconstructor(pathOrStore: string | Store, options?: RocksDatabaseOptions) {\n\t\tif (typeof pathOrStore === 'string') {\n\t\t\tsuper(new Store(pathOrStore, options));\n\t\t} else if (pathOrStore instanceof Store) {\n\t\t\tsuper(pathOrStore);\n\t\t} else {\n\t\t\tthrow new TypeError('Invalid database path or store');\n\t\t}\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.db.opened) {\n\t\t\treturn Promise.reject(new Error('Database not open'));\n\t\t}\n\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.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\tif (this.store.encoder?.structures !== undefined) {\n\t\t\tthis.store.encoder.structures = [];\n\t\t}\n\n\t\treturn this.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 * 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// committed\n\n\tasync drop(): Promise<void> {\n\t\tif (!this.store.db.opened) {\n\t\t\treturn Promise.reject(new Error('Database not open'));\n\t\t}\n\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\tif (!this.store.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\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// flushed\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 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 {\n\t\treturn this.store.db.getDBProperty(propertyName);\n\t}\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 {\n\t\treturn this.store.db.getDBIntProperty(propertyName);\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\tgetStats() {\n\t\treturn { free: {}, root: {} };\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 * 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 * 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\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((txn: Transaction) => {\n\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// so we don't want to use the transaction's getBinarySync()\n\t\t\t\t\t\tconst existingStructuresBuffer = this.getBinarySync(sharedStructuresKey);\n\t\t\t\t\t\tconst existingStructures = existingStructuresBuffer && store.decoder?.decode\n\t\t\t\t\t\t\t? store.decoder.decode(existingStructuresBuffer as BufferWithDataView)\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\tif (typeof isCompatible == 'function') {\n\t\t\t\t\t\t\tif (!isCompatible(existingStructures)) {\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} else if (existingStructures && existingStructures.length !== isCompatible) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttxn.putSync(sharedStructuresKey, structures);\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};\n\t\t\tstore.encoder.copyBuffers = true;\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\tpurgeLogs(options?: PurgeLogsOptions): string[] {\n\t\treturn this.store.db.purgeLogs(options);\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: (txn: Transaction) => T | PromiseLike<T>,\n\t\toptions?: TransactionOptions\n\t): Promise<T | PromiseLike<T>> {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\tconst txn = new Transaction(this.store, options);\n\t\tlet result: T | PromiseLike<T>;\n\n\t\ttry {\n\t\t\tthis.notify('begin-transaction');\n\t\t\tresult = await callback(txn);\n\t\t} catch (err) {\n\t\t\t// either a user error or a already aborted/committed error\n\t\t\ttry {\n\t\t\t\t// in the event of a user error, we need to abort the transaction\n\t\t\t\ttxn.abort();\n\t\t\t} catch (err) {\n\t\t\t\t// if the transaction was already aborted/committed, we can just return\n\t\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\t\treturn undefined as T | PromiseLike<T>;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// rethrow the user error\n\t\t\tthrow err;\n\t\t}\n\n\t\ttry {\n\t\t\tawait txn.commit();\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\treturn undefined as T;\n\t\t\t}\n\t\t\tthrow err;\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: (txn: Transaction) => T | PromiseLike<T>,\n\t\toptions?: TransactionOptions\n\t): T | PromiseLike<T> | undefined {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\tconst txn = new Transaction(this.store, options);\n\t\tlet result: T | PromiseLike<T>;\n\t\ttry {\n\t\t\tthis.notify('begin-transaction');\n\t\t\tresult = callback(txn);\n\t\t} catch (err) {\n\t\t\t// either a user error or a already aborted/committed error\n\t\t\ttry {\n\t\t\t\t// in the event of a user error, we need to abort the transaction\n\t\t\t\ttxn.abort();\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\t\treturn undefined as T;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\t// despite being 'sync', we need to support async operations\n\t\tif (\n\t\t\tresult && typeof result === 'object' && 'then' in result && typeof result.then === 'function'\n\t\t) {\n\t\t\treturn result.then((value) => {\n\t\t\t\ttry {\n\t\t\t\t\ttxn.commitSync();\n\t\t\t\t\treturn value as T;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\t\t\treturn undefined as T;\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\ttxn.commitSync();\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\treturn undefined as T;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\ttxn.abort();\n\t\t\t} catch {\n\t\t\t\t// ignore if abort fails\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\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 { closeSync, openSync, readSync, type Stats, statSync } from 'node:fs';\nimport { constants } from './load-binding.js';\n\nconst { TRANSACTION_LOG_TOKEN } = constants;\n\ninterface LogEntry {\n\tdata: Buffer;\n\tflags: number;\n\tlength: number;\n\ttimestamp?: number;\n}\n\ninterface TransactionLog {\n\tentries: LogEntry[];\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(path: string): 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\tthrow new Error(\n\t\t\t\t`Expected to read ${numBytes} bytes but only read ${bytesRead}, file offset: ${fileOffset}, file size: ${size}, file path: ${path}, buffer: ${\n\t\t\t\t\tbuffer.toString('hex')\n\t\t\t\t}`\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\n\t\t// read the entries\n\t\tconst entries: LogEntry[] = [];\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\tconst data = read(length);\n\t\t\tentries.push({ timestamp, length, flags, data });\n\t\t}\n\n\t\treturn { entries, 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{ start, end, exactStart, startFromLastFlushed, readUncommitted, exclusiveStart }:\n\t\t\tTransactionLogQueryOptions = {}\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\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) { // 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}\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}\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 = logBuffer!.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\tdataView = nextLogBuffer.dataView;\n\t\t\t\t\t\t\tlogBuffer = nextLogBuffer;\n\t\t\t\t\t\t\tif (latestLogId > logBuffer!.logId) {\n\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\tsize = logBuffer!.size\n\t\t\t\t\t\t\t\t\t?? (logBuffer!.size = transactionLog.getLogFileSize(logBuffer!.logId));\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tsize = latestSize; // use the latest position from loadLastPosition\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\n\t\t\t\twhile (position < size) {\n\t\t\t\t\t// advance to the next entry, reading the timestamp and the data\n\t\t\t\t\tdo {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\ttimestamp = dataView.getFloat64(position);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t(error as Error).message += ` at position ${position} of log ${\n\t\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t\t} (size=${size}, log buffer length=${logBuffer!.length})`;\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// skip past any leading zeros (which leads to a tiny float that is < 1e-303)\n\t\t\t\t\t} while (timestamp < 1 && ++position < size);\n\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\tconst length = dataView.getUint32(position + 8);\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) { // 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 { // no exact start, so just match on conditions\n\t\t\t\t\t\tmatchesRange = (exclusiveStart ? timestamp > start! : timestamp >= start!)\n\t\t\t\t\t\t\t&& 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\tlogBuffer = getLogMemoryMap(transactionLog, logBuffer!.logId + 1)!;\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) { // 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) { // 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 { RocksDatabase, type RocksDatabaseOptions } from './database.js';\nexport { DBIterator } from './dbi-iterator.js';\nexport type { Key } from './encoding.js';\nexport { constants, shutdown, type TransactionEntry, TransactionLog } from './load-binding.js';\nexport * from './parse-transaction-log.js';\nexport { type Context, Store } from './store.js';\nexport { Transaction } from './transaction.js';\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.cjs","names":["#context","#includeValues","orderedBinary","ExtendedIterable","#txn","#name","MsgpackEncoder","orderedBinary"],"sources":["../src/load-binding.ts","../src/util.ts","../src/dbi.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 { 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';\nimport type { IteratorOptions, RangeOptions } from './dbi.js';\nimport type { BufferWithDataView, Key } from './encoding.js';\nimport type { Context } from './store.js';\n\nexport type TransactionOptions = {\n\t/**\n\t * Whether to disable snapshots.\n\t *\n\t * @default false\n\t */\n\tdisableSnapshot?: boolean;\n};\n\nexport type NativeTransaction = {\n\tid: number;\n\tnew(context: NativeDatabase, options?: TransactionOptions): NativeTransaction;\n\tabort(): void;\n\tcommit(resolve: () => 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) => void,\n\t\treject: (err: Error) => void\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 & { dataView: DataView; logId: number; size: number };\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 = { timestamp: number; data: Buffer; endTxn: boolean };\n\nexport type TransactionLog = {\n\tnew(name: string): TransactionLog;\n\taddEntry(data: Buffer | Uint8Array, txnId?: number): void;\n\tquery(options?: TransactionLogQueryOptions): IterableIterator<TransactionEntry>;\n\t_getLastFlushed(): number;\n\t_getLastCommittedPosition(): Buffer;\n\t_getMemoryMapOfFile(sequenceId: number): LogBuffer | undefined;\n\tgetLogFileSize(sequenceId?: number): number;\n\t_getLastCommittedPosition(): Buffer;\n\t_findPosition(timestamp: number): number;\n\t_lastCommittedPosition: Float64Array;\n\t_logBuffers: Map<number, WeakRef<LogBuffer>>;\n\t_currentLogBuffer: LogBuffer;\n};\n\nexport declare class NativeIteratorCls<T> implements Iterator<T> {\n\tconstructor(context: Context, options: IteratorOptions);\n\tnext(): IteratorResult<T>;\n\treturn(): IteratorResult<T>;\n\tthrow(): IteratorResult<T>;\n}\n\nexport type NativeDatabaseMode = 'optimistic' | 'pessimistic';\n\nexport type NativeDatabaseOptions = {\n\tdisableWAL?: boolean;\n\tmode?: NativeDatabaseMode;\n\tname?: string;\n\tnoBlockCache?: boolean;\n\tparallelismThreads?: number;\n\ttransactionLogMaxAgeThreshold?: number;\n\ttransactionLogMaxSize?: number;\n\ttransactionLogRetentionMs?: number;\n\ttransactionLogsPath?: string;\n};\n\ntype ResolveCallback<T> = (value: T) => void;\ntype RejectCallback = (err: Error) => void;\n\nexport type UserSharedBufferCallback = () => void;\n\nexport type PurgeLogsOptions = { destroy?: boolean; name?: string };\n\nexport type NativeDatabase = {\n\tnew(): NativeDatabase;\n\taddListener(event: string, callback: (...args: any[]) => void): void;\n\tclear(resolve: ResolveCallback<void>, reject: RejectCallback): void;\n\tclearSync(): void;\n\tclose(): 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>,\n\t\treject: RejectCallback,\n\t\ttxnId?: number\n\t): number;\n\tgetCount(options?: RangeOptions, txnId?: number): number;\n\tgetDBIntProperty(propertyName: string): number;\n\tgetDBProperty(propertyName: string): string;\n\tgetMonotonicTimestamp(): number;\n\tgetOldestSnapshotTimestamp(): number;\n\tgetSync(keyLengthOrKeyBuffer: number | Buffer, flags: number, txnId?: number): 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\tpurgeLogs(options?: PurgeLogsOptions): string[];\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\ttryLock(key: BufferWithDataView, callback?: () => void): boolean;\n\tunlock(key: BufferWithDataView): void;\n\tuseLog(name: string): TransactionLog;\n\twithLock(key: BufferWithDataView, callback: () => void | Promise<void>): Promise<void>;\n};\n\nexport type RocksDatabaseConfig = { blockCacheSize?: number };\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\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 = (!report?.header || !report.header.glibcVersionRuntime) &&\n\t\t\t\t\tArray.isArray(report?.sharedObjects) && report.sharedObjects.some(obj =>\n\t\t\t\t\t\tobj.includes('libc.musl-') || obj.includes('ld-musl-')\n\t\t\t\t\t);\n\t\t\t}\n\t\t\tisMusl = isMusl || execSync('ldd --version', { encoding: 'utf8' }).includes('musl');\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\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 constants: {\n\tTRANSACTION_LOG_TOKEN: number;\n\tTRANSACTION_LOG_FILE_HEADER_SIZE: number;\n\tTRANSACTION_LOG_ENTRY_HEADER_SIZE: number;\n\tONLY_IF_IN_MEMORY_CACHE_FLAG: number;\n\tNOT_IN_MEMORY_CACHE_FLAG: number;\n\tALWAYS_CREATE_NEW_BUFFER_FLAG: number;\n} = binding.constants;\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 version: string = binding.version;\nexport const shutdown: () => void = binding.shutdown;\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 type { NativeTransaction, TransactionLog } from './load-binding.js';\nimport type { Context, GetOptions, PutOptions, Store } 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// limit?: 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: Context;\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(() => this.getBinaryFast(key, options), result => {\n\t\t\t\tif (result === undefined) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\tif (options?.skipDecode) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\treturn this.store.decodeValue(result as BufferWithDataView);\n\t\t\t});\n\t\t}\n\n\t\treturn when(\n\t\t\t() => this.getBinary(key, options),\n\t\t\tresult =>\n\t\t\t\tresult === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: (this.store.encoding === 'binary' || !this.store.decoder || options?.skipDecode)\n\t\t\t\t\t? result\n\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 | 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, this.store.getTxnId(options));\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 | 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 | 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, this.store.getTxnId(options));\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 | 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.getRange(this.#context, { ...options, values: false }).map(item => item.key);\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.getCount(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 ? undefined : 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 ? this.store.decodeValue(result as BufferWithDataView) : undefined;\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 as DBITransactional);\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 as DBITransactional);\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: () => 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","import type { IteratorOptions } from './dbi.js';\nimport type { BufferWithDataView, Key } from './encoding.js';\nimport type { Store } from './store.js';\n\nexport interface DBIteratorValue<T> {\n\tkey: Key;\n\tvalue: T;\n}\n\n/**\n * Wraps an iterator, namely the `NativeIterator` class, and decodes the key\n * and value.\n */\nexport class DBIterator<T> implements Iterator<DBIteratorValue<T>> {\n\titerator: Iterator<DBIteratorValue<T>>;\n\tstore: Store;\n\t#includeValues: boolean;\n\n\tconstructor(iterator: Iterator<DBIteratorValue<T>>, store: Store, options?: IteratorOptions & T) {\n\t\tthis.iterator = iterator;\n\t\tthis.store = store;\n\t\tthis.#includeValues = options?.values ?? true;\n\t}\n\n\t[Symbol.iterator](): Iterator<DBIteratorValue<T>> {\n\t\treturn this;\n\t}\n\n\tnext(...[_value]: [] | [any]): IteratorResult<DBIteratorValue<T>> {\n\t\tconst result = this.iterator.next();\n\t\tif (result.done) {\n\t\t\treturn result;\n\t\t}\n\n\t\tconst value: Partial<DBIteratorValue<T>> = {};\n\t\tvalue.key = this.store.decodeKey(result.value.key as Buffer);\n\t\tif (this.#includeValues) {\n\t\t\tvalue.value = this.store.decodeValue(result.value.value as BufferWithDataView);\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\tif (this.iterator.return) {\n\t\t\treturn this.iterator.return(value);\n\t\t}\n\t\treturn { done: true, value };\n\t}\n\n\tthrow(err: unknown): IteratorResult<DBIteratorValue<T>, any> {\n\t\tif (this.iterator.throw) {\n\t\t\treturn this.iterator.throw(err);\n\t\t}\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\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 { ExtendedIterable } from '@harperfast/extended-iterable';\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\ttype TransactionLog,\n\ttype UserSharedBufferCallback,\n} from './load-binding.js';\nimport { parseDuration } from './util.js';\n\nconst { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG } =\n\tconstants;\nconst KEY_BUFFER_SIZE = 4096;\nexport const KEY_BUFFER: BufferWithDataView = createFixedBuffer(KEY_BUFFER_SIZE);\nexport const VALUE_BUFFER: BufferWithDataView = createFixedBuffer(64 * 1024);\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 Context = NativeDatabase | NativeTransaction;\n\n/**\n * Options for the `Store` class.\n */\nexport interface StoreOptions\n\textends Omit<NativeDatabaseOptions, 'mode' | 'transactionLogRetentionMs'>\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// readOnly?: 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 & { cancel: () => void; notify: () => void };\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 * This store should not be shared between `RocksDatabase` instances.\n */\nexport class Store {\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 * Whether to disable the write ahead log.\n\t */\n\tdisableWAL: 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 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.\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 * 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 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 * 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.decoder = options?.decoder ?? null;\n\t\tthis.disableWAL = options?.disableWAL ?? 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.name = options?.name ?? 'default';\n\t\tthis.noBlockCache = options?.noBlockCache;\n\t\tthis.parallelismThreads = options?.parallelismThreads ?? 1;\n\t\tthis.path = path;\n\t\tthis.pessimistic = options?.pessimistic ?? false;\n\t\tthis.randomAccessStructure = options?.randomAccessStructure ?? false;\n\t\tthis.readKey = readKey;\n\t\tthis.sharedStructuresKey = options?.sharedStructuresKey;\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.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 * 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: NativeDatabase | NativeTransaction,\n\t\tkey: Key,\n\t\talwaysCreateNewBuffer: boolean = false,\n\t\ttxnId?: number\n\t): any | undefined {\n\t\tconst keyParam = getKeyParam(this.encodeKey(key));\n\t\tlet flags = 0;\n\t\tif (alwaysCreateNewBuffer) { // 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\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(keyParam, flags | ONLY_IF_IN_MEMORY_CACHE_FLAG, txnId);\n\t\tif (typeof result === 'number') { // 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);\n\t\t\t\t});\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: NativeDatabase | NativeTransaction, options?: RangeOptions): 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\tgetRange(\n\t\tcontext: NativeDatabase | NativeTransaction,\n\t\toptions?: IteratorOptions & DBITransactional\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\toptions = { ...options };\n\n\t\tconst unencodedStartKey = options.key ?? options.start;\n\n\t\tif (unencodedStartKey !== undefined) {\n\t\t\tconst start = this.encodeKey(unencodedStartKey);\n\t\t\toptions.start = Buffer.from(start.subarray(start.start, start.end));\n\t\t}\n\n\t\tif (options.key !== undefined) {\n\t\t\toptions.end = options.start;\n\t\t\toptions.inclusiveEnd = true;\n\t\t} else if (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\tif (options.reverse) {\n\t\t\t// reverse the start and end keys\n\t\t\tconst start = options.start;\n\t\t\toptions.start = options.end;\n\t\t\toptions.end = start;\n\n\t\t\t// reverse the exclusive start and end flags\n\t\t\toptions.exclusiveStart = options.exclusiveStart ?? true;\n\t\t\toptions.inclusiveEnd = options.inclusiveEnd ?? true;\n\t\t}\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, options) as Iterator<DBIteratorValue<any>>,\n\t\t\t\tthis,\n\t\t\t\toptions\n\t\t\t)\n\t\t);\n\t}\n\n\tgetSync(\n\t\tcontext: NativeDatabase | NativeTransaction,\n\t\tkey: Key,\n\t\talwaysCreateNewBuffer: boolean = false,\n\t\toptions?: GetOptions & DBITransactional\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\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(keyParam, flags, this.getTxnId(options));\n\t\tif (typeof result === 'number') { // 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 ((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\tthis.db.open(this.path, {\n\t\t\tdisableWAL: this.disableWAL,\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\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});\n\n\t\treturn false;\n\t}\n\n\tputSync(\n\t\tcontext: NativeDatabase | NativeTransaction,\n\t\tkey: Key,\n\t\tvalue: any,\n\t\toptions?: PutOptions & DBITransactional\n\t): 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(\n\t\tcontext: NativeDatabase | NativeTransaction,\n\t\tkey: Key,\n\t\toptions?: DBITransactional | undefined\n\t): 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: NativeDatabase | NativeTransaction, 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\treturn context.useLog(String(name));\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 * 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 { NativeTransaction, type TransactionOptions } from './load-binding.js';\nimport { Store } from './store.js';\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?: TransactionOptions) {\n\t\tconst txn = new NativeTransaction(store.db, options);\n\t\tsuper(store, txn);\n\t\tthis.#txn = txn;\n\t}\n\n\t/**\n\t * Abort the transaction.\n\t */\n\tabort(): void {\n\t\tthis.#txn.abort();\n\t}\n\n\t/**\n\t * Commit the transaction.\n\t */\n\tasync commit(): Promise<void> {\n\t\ttry {\n\t\t\tawait new Promise<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} 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} 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 * 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 { Encoder as MsgpackEncoder } from 'msgpackr';\nimport * as orderedBinary from 'ordered-binary';\nimport { DBI, type DBITransactional } from './dbi.js';\nimport type { BufferWithDataView, Encoder, EncoderFunction, Key } from './encoding.js';\nimport {\n\tconfig,\n\ttype PurgeLogsOptions,\n\ttype RocksDatabaseConfig,\n\ttype TransactionOptions,\n} from './load-binding.js';\nimport {\n\ttype ArrayBufferWithNotify,\n\tKEY_BUFFER,\n\tStore,\n\ttype StoreOptions,\n\ttype UserSharedBufferOptions,\n\tVALUE_BUFFER,\n} from './store.js';\nimport { Transaction } from './transaction.js';\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\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\tif (typeof pathOrStore === 'string') {\n\t\t\tsuper(new Store(pathOrStore, options));\n\t\t} else if (pathOrStore instanceof Store) {\n\t\t\tsuper(pathOrStore);\n\t\t} else {\n\t\t\tthrow new TypeError('Invalid database path or store');\n\t\t}\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.db.opened) {\n\t\t\treturn Promise.reject(new Error('Database not open'));\n\t\t}\n\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.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\n\t\tif (this.store.encoder?.structures !== undefined) {\n\t\t\tthis.store.encoder.structures = [];\n\t\t}\n\n\t\treturn this.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 * 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// committed\n\n\tasync drop(): Promise<void> {\n\t\tif (!this.store.db.opened) {\n\t\t\treturn Promise.reject(new Error('Database not open'));\n\t\t}\n\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\tif (!this.store.db.opened) {\n\t\t\tthrow new Error('Database not open');\n\t\t}\n\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// flushed\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 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 {\n\t\treturn this.store.db.getDBProperty(propertyName);\n\t}\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 {\n\t\treturn this.store.db.getDBIntProperty(propertyName);\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\tgetStats() {\n\t\treturn { free: {}, root: {} };\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 * 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 * 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\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((txn: Transaction) => {\n\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// so we don't want to use the transaction's getBinarySync()\n\t\t\t\t\t\tconst existingStructuresBuffer = this.getBinarySync(sharedStructuresKey);\n\t\t\t\t\t\tconst existingStructures = existingStructuresBuffer && store.decoder?.decode\n\t\t\t\t\t\t\t? store.decoder.decode(existingStructuresBuffer as BufferWithDataView)\n\t\t\t\t\t\t\t: undefined;\n\t\t\t\t\t\tif (typeof isCompatible == 'function') {\n\t\t\t\t\t\t\tif (!isCompatible(existingStructures)) {\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} else if (existingStructures && existingStructures.length !== isCompatible) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttxn.putSync(sharedStructuresKey, structures);\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};\n\t\t\tstore.encoder.copyBuffers = true;\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\tpurgeLogs(options?: PurgeLogsOptions): string[] {\n\t\treturn this.store.db.purgeLogs(options);\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: (txn: Transaction) => T | PromiseLike<T>,\n\t\toptions?: TransactionOptions\n\t): Promise<T | PromiseLike<T>> {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\tconst txn = new Transaction(this.store, options);\n\t\tlet result: T | PromiseLike<T>;\n\n\t\ttry {\n\t\t\tthis.notify('begin-transaction');\n\t\t\tresult = await callback(txn);\n\t\t} catch (err) {\n\t\t\t// either a user error or a already aborted/committed error\n\t\t\ttry {\n\t\t\t\t// in the event of a user error, we need to abort the transaction\n\t\t\t\ttxn.abort();\n\t\t\t} catch (err) {\n\t\t\t\t// if the transaction was already aborted/committed, we can just return\n\t\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\t\treturn undefined as T | PromiseLike<T>;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// rethrow the user error\n\t\t\tthrow err;\n\t\t}\n\n\t\ttry {\n\t\t\tawait txn.commit();\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\treturn undefined as T;\n\t\t\t}\n\t\t\tthrow err;\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: (txn: Transaction) => T | PromiseLike<T>,\n\t\toptions?: TransactionOptions\n\t): T | PromiseLike<T> | undefined {\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new TypeError('Callback must be a function');\n\t\t}\n\n\t\tconst txn = new Transaction(this.store, options);\n\t\tlet result: T | PromiseLike<T>;\n\t\ttry {\n\t\t\tthis.notify('begin-transaction');\n\t\t\tresult = callback(txn);\n\t\t} catch (err) {\n\t\t\t// either a user error or a already aborted/committed error\n\t\t\ttry {\n\t\t\t\t// in the event of a user error, we need to abort the transaction\n\t\t\t\ttxn.abort();\n\t\t\t} catch (err) {\n\t\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\t\treturn undefined as T;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\n\n\t\t// despite being 'sync', we need to support async operations\n\t\tif (\n\t\t\tresult && typeof result === 'object' && 'then' in result && typeof result.then === 'function'\n\t\t) {\n\t\t\treturn result.then((value) => {\n\t\t\t\ttry {\n\t\t\t\t\ttxn.commitSync();\n\t\t\t\t\treturn value as T;\n\t\t\t\t} catch (err) {\n\t\t\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\t\t\treturn undefined as T;\n\t\t\t\t\t}\n\t\t\t\t\tthrow err;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\ttry {\n\t\t\ttxn.commitSync();\n\t\t\treturn result;\n\t\t} catch (err) {\n\t\t\tif (err instanceof Error && 'code' in err && err.code === 'ERR_ALREADY_ABORTED') {\n\t\t\t\treturn undefined as T;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\ttxn.abort();\n\t\t\t} catch {\n\t\t\t\t// ignore if abort fails\n\t\t\t}\n\t\t\tthrow err;\n\t\t}\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 { closeSync, openSync, readSync, type Stats, statSync } from 'node:fs';\nimport { constants } from './load-binding.js';\n\nconst { TRANSACTION_LOG_TOKEN } = constants;\n\ninterface LogEntry {\n\tdata: Buffer;\n\tflags: number;\n\tlength: number;\n\ttimestamp?: number;\n}\n\ninterface TransactionLog {\n\tentries: LogEntry[];\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(path: string): 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\tthrow new Error(\n\t\t\t\t`Expected to read ${numBytes} bytes but only read ${bytesRead}, file offset: ${fileOffset}, file size: ${size}, file path: ${path}, buffer: ${\n\t\t\t\t\tbuffer.toString('hex')\n\t\t\t\t}`\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\n\t\t// read the entries\n\t\tconst entries: LogEntry[] = [];\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\tconst data = read(length);\n\t\t\tentries.push({ timestamp, length, flags, data });\n\t\t}\n\n\t\treturn { entries, 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{ start, end, exactStart, startFromLastFlushed, readUncommitted, exclusiveStart }:\n\t\t\tTransactionLogQueryOptions = {}\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\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) { // 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}\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}\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 = logBuffer!.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\tdataView = nextLogBuffer.dataView;\n\t\t\t\t\t\t\tlogBuffer = nextLogBuffer;\n\t\t\t\t\t\t\tif (latestLogId > logBuffer!.logId) {\n\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\tsize = logBuffer!.size\n\t\t\t\t\t\t\t\t\t?? (logBuffer!.size = transactionLog.getLogFileSize(logBuffer!.logId));\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tsize = latestSize; // use the latest position from loadLastPosition\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\n\t\t\t\twhile (position < size) {\n\t\t\t\t\t// advance to the next entry, reading the timestamp and the data\n\t\t\t\t\tdo {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\ttimestamp = dataView.getFloat64(position);\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t(error as Error).message += ` at position ${position} of log ${\n\t\t\t\t\t\t\t\tlogBuffer!.logId\n\t\t\t\t\t\t\t} (size=${size}, log buffer length=${logBuffer!.length})`;\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// skip past any leading zeros (which leads to a tiny float that is < 1e-303)\n\t\t\t\t\t} while (timestamp < 1 && ++position < size);\n\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\tconst length = dataView.getUint32(position + 8);\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) { // 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 { // no exact start, so just match on conditions\n\t\t\t\t\t\tmatchesRange = (exclusiveStart ? timestamp > start! : timestamp >= start!)\n\t\t\t\t\t\t\t&& 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\tlogBuffer = getLogMemoryMap(transactionLog, logBuffer!.logId + 1)!;\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) { // 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) { // 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 { RocksDatabase, type RocksDatabaseOptions } from './database.js';\nexport { DBIterator } from './dbi-iterator.js';\nexport type { IteratorOptions } from './dbi.js';\nexport type { Key } from './encoding.js';\nexport { constants, shutdown, type TransactionEntry, TransactionLog } from './load-binding.js';\nexport * from './parse-transaction-log.js';\nexport { type Context, Store } 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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"}
|