@harperfast/rocksdb-js 2.8.0 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -66,6 +66,26 @@ const binding = req(locateBinding());
66
66
  */
67
67
  const BackgroundError = binding.BackgroundError;
68
68
  const config = binding.config;
69
+ /**
70
+ * Reads the live state of the process-wide `WriteBufferManager`: its budget,
71
+ * charged memory, mutable share, stall state, and attached column-family
72
+ * inventory. The manager is shared by every database and worker thread in the
73
+ * process.
74
+ *
75
+ * A WriteBufferManager stall does not pass through RocksDB's `WriteController`,
76
+ * so it is not reflected by `rocksdb.stall.micros`, `db.isWriteStalled()`, or
77
+ * the `'writeStall'` event. Use `stallActive` to distinguish this condition from
78
+ * an idle database.
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * const wbm = getWriteBufferManagerStats();
83
+ * if (wbm.stallActive) {
84
+ * log.warn(`writes stalled for ${wbm.stallActiveMs}ms`);
85
+ * }
86
+ * ```
87
+ */
88
+ const getWriteBufferManagerStats = binding.getWriteBufferManagerStats;
69
89
  const FRESH_VERSION_FLAG$1 = binding.constants.FRESH_VERSION_FLAG;
70
90
  const addGlobalListener = binding.addListener;
71
91
  const removeGlobalListener = binding.removeListener;
@@ -114,6 +134,8 @@ const transactionLogMapCount = binding.transactionLogMapCount;
114
134
  * disarm. Used by the ERR_TRY_AGAIN retry regression test.
115
135
  */
116
136
  const forceTryAgainForTesting = binding.forceTryAgainForTesting;
137
+ /** Delays one selected watchdog join in the concurrent-shutdown regression test. */
138
+ const setWriteBufferManagerJoinDelayForTesting = binding.setWriteBufferManagerJoinDelayForTesting;
117
139
  /**
118
140
  * Creates a native file lock using the specified file path (`flock` on POSIX,
119
141
  * `LockFileEx` on Windows), creating the file and any missing parent
@@ -642,14 +664,12 @@ function parseDuration(duration) {
642
664
  num *= 1e3;
643
665
  break;
644
666
  case "m":
645
- num *= 1e3 * 60;
667
+ num *= 6e4;
646
668
  break;
647
669
  case "h":
648
- num *= 1e3 * 60 * 60;
649
- break;
650
- case "d":
651
- num *= 1e3 * 60 * 60 * 24;
670
+ num *= 36e5;
652
671
  break;
672
+ case "d": num *= 864e5;
653
673
  }
654
674
  result += num;
655
675
  }
@@ -1352,10 +1372,10 @@ function createFixedBuffer(size) {
1352
1372
 
1353
1373
  //#endregion
1354
1374
  //#region src/store.ts
1355
- const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG, FRESH_VERSION_FLAG, POPULATE_VERSION_FLAG, ITERATOR_REVERSE_FLAG, ITERATOR_INCLUSIVE_END_FLAG, ITERATOR_EXCLUSIVE_START_FLAG, ITERATOR_INCLUDE_VALUES_FLAG, ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG, ITERATOR_CONTEXT_IS_TRANSACTION_FLAG } = constants;
1375
+ const { ONLY_IF_IN_MEMORY_CACHE_FLAG, NOT_IN_MEMORY_CACHE_FLAG, ALWAYS_CREATE_NEW_BUFFER_FLAG, FRESH_VERSION_FLAG, POPULATE_VERSION_FLAG, ITERATOR_REVERSE_FLAG, ITERATOR_INCLUSIVE_END_FLAG, ITERATOR_EXCLUSIVE_START_FLAG, ITERATOR_INCLUDE_VALUES_FLAG, ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG, ITERATOR_CONTEXT_IS_TRANSACTION_FLAG, ITERATOR_HAS_TRANSACTION_ID_FLAG } = constants;
1356
1376
  const KEY_BUFFER_SIZE = 4096;
1357
1377
  const KEY_BUFFER = createFixedBuffer(KEY_BUFFER_SIZE);
1358
- const VALUE_BUFFER = createFixedBuffer(64 * 1024);
1378
+ const VALUE_BUFFER = createFixedBuffer(65536);
1359
1379
  /**
1360
1380
  * Backing buffer for the shared iterator state. Layout (Uint32Array view):
1361
1381
  * [0] = key length written into KEY_BUFFER by the most recent iterator step
@@ -1363,7 +1383,7 @@ const VALUE_BUFFER = createFixedBuffer(64 * 1024);
1363
1383
  */
1364
1384
  const ITERATOR_STATE_BUFFER = Buffer.allocUnsafeSlow(8);
1365
1385
  const ITERATOR_STATE = new Uint32Array(ITERATOR_STATE_BUFFER.buffer, ITERATOR_STATE_BUFFER.byteOffset, 2);
1366
- const MAX_KEY_SIZE = 1024 * 1024;
1386
+ const MAX_KEY_SIZE = 1048576;
1367
1387
  const SAVE_BUFFER_SIZE = 8192;
1368
1388
  /**
1369
1389
  * Normalizes the public `compression` option into the primitive fields the
@@ -1398,6 +1418,15 @@ function normalizeCompression(option) {
1398
1418
  };
1399
1419
  }
1400
1420
  /**
1421
+ * Whether `codec` is a pre-constructed encoder/decoder instance that `open()`
1422
+ * would reuse as-is (rather than instantiate fresh from an `Encoder` factory).
1423
+ * Such an instance carries per-column-family mutable state (its `name`, msgpack
1424
+ * `structures`), so it cannot be shared across column families.
1425
+ */
1426
+ function sharesMutableCodec(codec) {
1427
+ return codec != null && typeof codec === "object" && typeof codec.Encoder !== "function" && (typeof codec.encode === "function" || typeof codec.decode === "function");
1428
+ }
1429
+ /**
1401
1430
  * A store wraps the `NativeDatabase` binding and database settings so that a
1402
1431
  * single database instance can be shared between the main `RocksDatabase`
1403
1432
  * instance and the `Transaction` instance.
@@ -1416,6 +1445,13 @@ var Store = class {
1416
1445
  */
1417
1446
  #claimed = false;
1418
1447
  /**
1448
+ * Shallow snapshot of the options this store was constructed with, used by
1449
+ * `createColumnFamilyStore()` to derive sibling column-family stores. Snapshot
1450
+ * (not the caller's object) so later mutations of the caller's options don't
1451
+ * leak into derived views.
1452
+ */
1453
+ #columnFamilyOptions;
1454
+ /**
1419
1455
  * The database instance.
1420
1456
  */
1421
1457
  db;
@@ -1551,6 +1587,11 @@ var Store = class {
1551
1587
  */
1552
1588
  path;
1553
1589
  /**
1590
+ * The open database's resolved filesystem identity, read once from
1591
+ * `NativeDatabase.identityPath`. `undefined` until opened.
1592
+ */
1593
+ identityPath;
1594
+ /**
1554
1595
  * Whether to use pessimistic locking for transactions. When `true`,
1555
1596
  * transactions will fail as soon as a conflict is detected. When `false`,
1556
1597
  * transactions will only fail when `commit()` is called.
@@ -1564,6 +1605,13 @@ var Store = class {
1564
1605
  */
1565
1606
  readOnly;
1566
1607
  /**
1608
+ * The secondary instance's workspace directory when the database is opened
1609
+ * as a secondary (see `RocksDatabaseOptions.secondaryPath`); `undefined`
1610
+ * otherwise. A secondary is read-only, so `readOnly` is `true` whenever
1611
+ * this is set.
1612
+ */
1613
+ secondaryPath;
1614
+ /**
1567
1615
  * Encoder specific flag used to signal that the encoder should use a random
1568
1616
  * access structure.
1569
1617
  */
@@ -1649,7 +1697,10 @@ var Store = class {
1649
1697
  this.parallelismThreads = options?.parallelismThreads;
1650
1698
  this.path = path;
1651
1699
  this.pessimistic = options?.pessimistic ?? false;
1652
- this.readOnly = options?.readOnly ?? false;
1700
+ const secondaryPath = options?.secondaryPath ?? void 0;
1701
+ if (secondaryPath !== void 0 && options?.readOnly === false) throw new Error("A secondary open is read-only; secondaryPath cannot be combined with readOnly: false");
1702
+ this.readOnly = options?.readOnly ?? secondaryPath !== void 0;
1703
+ this.secondaryPath = secondaryPath;
1653
1704
  this.randomAccessStructure = options?.randomAccessStructure ?? false;
1654
1705
  this.readKey = readKey;
1655
1706
  this.sharedStructuresKey = options?.sharedStructuresKey;
@@ -1661,6 +1712,36 @@ var Store = class {
1661
1712
  this.verificationTable = options?.verificationTable;
1662
1713
  this.writeBufferSize = options?.writeBufferSize;
1663
1714
  this.writeKey = writeKey;
1715
+ this.#columnFamilyOptions = options ? { ...options } : void 0;
1716
+ }
1717
+ /**
1718
+ * Creates an independent `Store` for another column family of the same
1719
+ * database, used by {@link RocksDatabase#use}. The returned store shares the
1720
+ * underlying database but must have its own codec state: a mutable
1721
+ * encoder/decoder instance cannot be shared across column families (opening a
1722
+ * view mutates the encoder's `name`, and clearing a view resets its
1723
+ * `structures`), so a pre-constructed instance is rejected here — supply an
1724
+ * encoder factory (`{ Encoder }`) or a named `encoding` instead.
1725
+ *
1726
+ * Override this in a `Store` subclass whose constructor cannot be recreated
1727
+ * from `(path, options)` (e.g. it takes injected dependencies) or that needs
1728
+ * to control how a view's codec state is built.
1729
+ *
1730
+ * @param name - The column family name for the derived store.
1731
+ * @param options - Options overriding this store's, for the derived store.
1732
+ * @returns A new, independent `Store` bound to `name`.
1733
+ */
1734
+ createColumnFamilyStore(name, options) {
1735
+ const derived = {
1736
+ ...this.#columnFamilyOptions,
1737
+ ...options,
1738
+ name
1739
+ };
1740
+ if (sharesMutableCodec(derived.encoder) || sharesMutableCodec(derived.decoder)) throw new Error("Cannot derive a column family view from a Store configured with a pre-constructed encoder/decoder instance — its mutable state would be shared across column families. Provide an encoder factory (`{ Encoder }`) or a named `encoding`, or override `Store#createColumnFamilyStore`.");
1741
+ const StoreClass = this.constructor;
1742
+ const store = new StoreClass(this.path, derived);
1743
+ if (store.name !== name) throw new Error(`Store#createColumnFamilyStore produced a store bound to "${store.name}" instead of "${name}"; a custom Store must forward options to super() or override this method.`);
1744
+ return store;
1664
1745
  }
1665
1746
  /**
1666
1747
  * Closes the database.
@@ -1842,6 +1923,7 @@ var Store = class {
1842
1923
  let endUnencoded = options?.key ?? options?.end;
1843
1924
  const includeValues = options?.values ?? true;
1844
1925
  const reverse = options?.reverse ?? false;
1926
+ const txnId = this.getTxnId(options);
1845
1927
  let exclusiveStart = options?.exclusiveStart ?? false;
1846
1928
  let inclusiveEnd = options?.inclusiveEnd ?? false;
1847
1929
  if (options?.key !== void 0) inclusiveEnd = true;
@@ -1860,13 +1942,15 @@ var Store = class {
1860
1942
  startKeyEnd = this.writeKey(startUnencoded, keyBuffer, 0);
1861
1943
  if (startKeyEnd === 0) throw new Error("Zero length key is not allowed");
1862
1944
  }
1863
- if (endUnencoded !== void 0) if (endUnencoded === startUnencoded) {
1864
- endKeyStart = 0;
1865
- endKeyEnd = startKeyEnd;
1866
- } else {
1867
- endKeyStart = startKeyEnd;
1868
- endKeyEnd = this.writeKey(endUnencoded, keyBuffer, endKeyStart);
1869
- if (endKeyEnd === endKeyStart) throw new Error("Zero length key is not allowed");
1945
+ if (endUnencoded !== void 0) {
1946
+ if (endUnencoded === startUnencoded) {
1947
+ endKeyStart = 0;
1948
+ endKeyEnd = startKeyEnd;
1949
+ } else {
1950
+ endKeyStart = startKeyEnd;
1951
+ endKeyEnd = this.writeKey(endUnencoded, keyBuffer, endKeyStart);
1952
+ if (endKeyEnd === endKeyStart) throw new Error("Zero length key is not allowed");
1953
+ }
1870
1954
  }
1871
1955
  let flags = 0;
1872
1956
  if (reverse) flags |= ITERATOR_REVERSE_FLAG;
@@ -1875,8 +1959,9 @@ var Store = class {
1875
1959
  if (includeValues) flags |= ITERATOR_INCLUDE_VALUES_FLAG;
1876
1960
  if (includeValues && !this.decoderCopies) flags |= ITERATOR_NEEDS_STABLE_VALUE_BUFFER_FLAG;
1877
1961
  if (context !== this.db) flags |= ITERATOR_CONTEXT_IS_TRANSACTION_FLAG;
1962
+ if (txnId !== void 0) flags |= ITERATOR_HAS_TRANSACTION_ID_FLAG;
1878
1963
  const advancedOptions = options !== void 0 && (options.adaptiveReadahead !== void 0 || options.asyncIO !== void 0 || options.autoReadaheadSize !== void 0 || options.backgroundPurgeOnIteratorCleanup !== void 0 || options.fillCache !== void 0 || options.readaheadSize !== void 0 || options.tailing !== void 0) ? options : void 0;
1879
- return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions), this, includeValues, options?.limit));
1964
+ return new ExtendedIterable(new DBIterator(new NativeIterator(context, flags, startKeyEnd, endKeyStart, endKeyEnd, advancedOptions, txnId), this, includeValues, options?.limit));
1880
1965
  }
1881
1966
  getSync(context, key, alwaysCreateNewBuffer = false, options) {
1882
1967
  const keyParam = getKeyParam(this.encodeKey(key));
@@ -1897,9 +1982,12 @@ var Store = class {
1897
1982
  */
1898
1983
  getTxnId(options) {
1899
1984
  let txnId;
1900
- if (!this.readOnly && options?.transaction) {
1901
- txnId = options.transaction.id;
1985
+ const transaction = options?.transaction;
1986
+ if (!this.readOnly && transaction) {
1987
+ txnId = transaction.id;
1902
1988
  if (txnId === void 0) throw new TypeError("Invalid transaction");
1989
+ if (transaction.store === void 0) throw new TypeError("Invalid transaction");
1990
+ if (this.identityPath !== void 0 && transaction.store.identityPath !== this.identityPath) throw new TypeError("Transaction belongs to a different database");
1903
1991
  }
1904
1992
  return txnId;
1905
1993
  }
@@ -1957,7 +2045,10 @@ var Store = class {
1957
2045
  * are performed.
1958
2046
  */
1959
2047
  open() {
1960
- if (this.db.opened) return true;
2048
+ if (this.db.opened) {
2049
+ this.identityPath = this.db.identityPath;
2050
+ return true;
2051
+ }
1961
2052
  const { compression, compressionLevel } = normalizeCompression(this.compression);
1962
2053
  this.db.open(this.path, {
1963
2054
  compression,
@@ -1976,6 +2067,7 @@ var Store = class {
1976
2067
  noBlockCache: this.noBlockCache,
1977
2068
  parallelismThreads: this.parallelismThreads,
1978
2069
  readOnly: this.readOnly,
2070
+ secondaryPath: this.secondaryPath,
1979
2071
  statsLevel: this.statsLevel,
1980
2072
  transactionLogMaxAgeThreshold: this.transactionLogMaxAgeThreshold,
1981
2073
  transactionLogMaxSize: this.transactionLogMaxSize,
@@ -1984,6 +2076,7 @@ var Store = class {
1984
2076
  verificationTable: this.verificationTable,
1985
2077
  writeBufferSize: this.writeBufferSize
1986
2078
  });
2079
+ this.identityPath = this.db.identityPath;
1987
2080
  return false;
1988
2081
  }
1989
2082
  putSync(context, key, value, options) {
@@ -2244,10 +2337,12 @@ var Transaction = class extends DBI {
2244
2337
  return err;
2245
2338
  }
2246
2339
  /**
2247
- * Returns the transaction start timestamp in seconds. Defaults to the time at which
2248
- * the transaction was created.
2340
+ * Returns the transaction timestamp in milliseconds since the Unix epoch. It
2341
+ * defaults to a process-wide monotonic value assigned when the transaction
2342
+ * was created. A producer may use this value as its write identity; the
2343
+ * transaction log uses it as the batch key.
2249
2344
  *
2250
- * @returns The transaction start timestamp in seconds.
2345
+ * @returns The transaction timestamp in milliseconds.
2251
2346
  */
2252
2347
  getTimestamp() {
2253
2348
  return this.#txn.getTimestamp();
@@ -2259,9 +2354,14 @@ var Transaction = class extends DBI {
2259
2354
  return this.#txn.id;
2260
2355
  }
2261
2356
  /**
2262
- * Set the transaction start timestamp in seconds.
2357
+ * Overrides the transaction timestamp in milliseconds since the Unix epoch.
2358
+ * Call this before reading the timestamp or staging writes when adopting an
2359
+ * origin timestamp for replication or replay. Once a write or log entry is
2360
+ * staged, the timestamp is frozen, but reapplying the same timestamp remains
2361
+ * idempotent while the transaction is pending. The value must be finite,
2362
+ * positive, and below 8640000000000000.
2263
2363
  *
2264
- * @param timestamp - The timestamp to set in seconds.
2364
+ * @param timestamp - The timestamp to set in milliseconds.
2265
2365
  */
2266
2366
  setTimestamp(timestamp) {
2267
2367
  this.#txn.setTimestamp(timestamp);
@@ -2295,9 +2395,23 @@ function backgroundErrorSeverityName(severity) {
2295
2395
  */
2296
2396
  var RocksDatabase = class RocksDatabase extends DBI {
2297
2397
  /**
2298
- * The name of the database.
2398
+ * The name of the database's column family.
2299
2399
  */
2300
2400
  #name;
2401
+ /**
2402
+ * Weak cache of column-family views opened via `use()`, keyed by column
2403
+ * family name — mirroring `useLog`'s get-or-create semantics. The reference
2404
+ * is weak so a view is never pinned for this database's lifetime: an
2405
+ * unreferenced view can be collected (closing its own `DBHandle`), and the
2406
+ * next `use()` transparently recreates it. `#columnFamilyRegistry` deletes an
2407
+ * entry once its view is collected so a churn of distinct names (e.g.
2408
+ * `use(uuid())`) does not grow the map without bound.
2409
+ */
2410
+ #columnFamilies = /* @__PURE__ */ new Map();
2411
+ #columnFamilyRegistry = new FinalizationRegistry((name) => {
2412
+ const ref = this.#columnFamilies.get(name);
2413
+ if (ref !== void 0 && ref.deref() === void 0) this.#columnFamilies.delete(name);
2414
+ });
2301
2415
  constructor(pathOrStore, options) {
2302
2416
  let store;
2303
2417
  if (typeof pathOrStore === "string") store = new Store(pathOrStore, options);
@@ -2305,7 +2419,7 @@ var RocksDatabase = class RocksDatabase extends DBI {
2305
2419
  else throw new TypeError("Invalid database path or store");
2306
2420
  store.claim();
2307
2421
  super(store);
2308
- this.#name = options?.name ?? "default";
2422
+ this.#name = this.store.name;
2309
2423
  }
2310
2424
  /**
2311
2425
  * Removes all data from the database asynchronously.
@@ -2524,6 +2638,40 @@ var RocksDatabase = class RocksDatabase extends DBI {
2524
2638
  static notify(event, ...args) {
2525
2639
  return globalNotify(event, args);
2526
2640
  }
2641
+ /**
2642
+ * Advances a secondary instance to the primary's current state by tailing
2643
+ * and replaying the primary's MANIFEST and WAL. A secondary does not see
2644
+ * the primary's writes until this (or {@link catchUpWithPrimarySync}) is
2645
+ * called. Concurrent reads through this handle remain safe while the
2646
+ * catch-up runs.
2647
+ *
2648
+ * Only valid on a database opened with the `secondaryPath` option; throws
2649
+ * with code `ERR_NOT_SECONDARY` otherwise.
2650
+ *
2651
+ * Advances the **database** view only. Against a cross-process primary,
2652
+ * transaction-log reads keep serving the stores discovered at open (a store
2653
+ * the primary creates later, and its appends, need a reopen); a primary in
2654
+ * the same process shares the store registry, so its stores and appends are
2655
+ * visible immediately. Either way a log entry can describe data this
2656
+ * handle's database view does not have yet — the log write completes before
2657
+ * the RocksDB commit for every writer, so consumers must tolerate the log
2658
+ * leading the database.
2659
+ *
2660
+ * Await one call before starting the next: the replay holds a libuv worker
2661
+ * for its whole duration and concurrent calls queue on a per-database mutex
2662
+ * while holding theirs, so overlapping catch-ups on a backlogged follower
2663
+ * can exhaust the default four-thread pool and stall unrelated I/O.
2664
+ */
2665
+ catchUpWithPrimary() {
2666
+ return new Promise((resolve, reject) => this.store.db.catchUpWithPrimary(resolve, reject));
2667
+ }
2668
+ /**
2669
+ * Synchronous version of {@link catchUpWithPrimary}. The replay runs on the
2670
+ * JS thread, so prefer the async form unless the caller is already blocking.
2671
+ */
2672
+ catchUpWithPrimarySync() {
2673
+ this.store.db.catchUpWithPrimarySync();
2674
+ }
2527
2675
  destroy() {
2528
2676
  this.store.db.destroy();
2529
2677
  }
@@ -2676,6 +2824,29 @@ var RocksDatabase = class RocksDatabase extends DBI {
2676
2824
  return this.store.db.getDBProperty(propertyName);
2677
2825
  }
2678
2826
  /**
2827
+ * Whether RocksDB is currently applying write backpressure to this database —
2828
+ * either delaying (rate-limiting) or fully stopping writes. This is the
2829
+ * authoritative, live pull counterpart to the `'writeStall'`
2830
+ * [event](../README.md#event-writestall): the event pushes per-column-family
2831
+ * transitions (and is rate-limited), while this reads the current state on
2832
+ * demand and can never be stale.
2833
+ *
2834
+ * The write controller is database-wide (shared across every column family),
2835
+ * so this reflects the database as a whole, not a single column family — a
2836
+ * stall triggered by any column family stops writes for all of them. Reads
2837
+ * `rocksdb.is-write-stopped` and `rocksdb.actual-delayed-write-rate`.
2838
+ *
2839
+ * @example
2840
+ * ```typescript
2841
+ * db.on('writeStall', (cf) => {
2842
+ * if (db.isWriteStalled()) log.warn(`writes throttled/blocked (triggered by ${cf})`);
2843
+ * });
2844
+ * ```
2845
+ */
2846
+ isWriteStalled() {
2847
+ return this.getDBIntProperty("rocksdb.is-write-stopped") === 1 || (this.getDBIntProperty("rocksdb.actual-delayed-write-rate") ?? 0) > 0;
2848
+ }
2849
+ /**
2679
2850
  * Retrieves the estimated number of keys in the database. This is an alias
2680
2851
  * for `db.estimateCount().count`; use `estimateCount()` for range support
2681
2852
  * and a confidence indicator.
@@ -2853,18 +3024,29 @@ var RocksDatabase = class RocksDatabase extends DBI {
2853
3024
  return this.store.listLogs();
2854
3025
  }
2855
3026
  /**
2856
- * The name of the database.
3027
+ * The name of the database's column family.
2857
3028
  */
2858
3029
  get name() {
2859
3030
  return this.#name;
2860
3031
  }
2861
3032
  /**
2862
- * Whether the database is open in readonly mode.
3033
+ * Whether the database is open in readonly mode. Also `true` for a
3034
+ * secondary instance (see {@link secondaryPath}), which is read-only by
3035
+ * construction.
2863
3036
  */
2864
3037
  get readOnly() {
2865
3038
  return this.store.readOnly;
2866
3039
  }
2867
3040
  /**
3041
+ * The secondary instance's workspace directory when the database was opened
3042
+ * as a secondary (a read-only follower of a live primary — see the
3043
+ * `secondaryPath` open option), or `undefined` for a regular or plain
3044
+ * read-only open.
3045
+ */
3046
+ get secondaryPath() {
3047
+ return this.store.secondaryPath;
3048
+ }
3049
+ /**
2868
3050
  * Sugar method for opening a database.
2869
3051
  *
2870
3052
  * @param pathOrStore - The filesystem path to the database or a custom store.
@@ -3137,6 +3319,57 @@ var RocksDatabase = class RocksDatabase extends DBI {
3137
3319
  return this.store.unlock(key);
3138
3320
  }
3139
3321
  /**
3322
+ * Returns a `RocksDatabase` bound to the `name` column family of this same
3323
+ * database, opening (and creating, if missing) the column family on first
3324
+ * use. This is a factory — create-and-open sugar — not a stateful switch: the
3325
+ * returned view is an independent instance whose own reads/writes target its
3326
+ * column family, while sharing the underlying database (so a transaction,
3327
+ * backup, or checkpoint still spans every column family). Because the view
3328
+ * opens its own handle, this database need not itself be open — a discarded
3329
+ * parent (`new RocksDatabase(path).use('events')`) still yields a valid,
3330
+ * opened view.
3331
+ *
3332
+ * Get-or-create, backed by a weak cache: `db.use('events') === db.use('events')`
3333
+ * while the view is still referenced **and open**, and calling with this
3334
+ * database's own column-family name returns `this`. A view that has been
3335
+ * closed (or garbage-collected — the cache does not pin it) is transparently
3336
+ * recreated on the next `use()`. Views are independent handles: closing this
3337
+ * database does not close them, and vice versa — the underlying database
3338
+ * stays open until every handle is closed or collected.
3339
+ *
3340
+ * The view's store is derived by {@link Store#createColumnFamilyStore}, which
3341
+ * builds an independent store of the same class with its own codec state (so
3342
+ * views never share a mutable encoder/decoder) and inherits the options this
3343
+ * store was constructed with; pass `options` to override them for this column
3344
+ * family. A database configured with a pre-constructed encoder/decoder
3345
+ * instance cannot derive views (its state would be shared) — use an encoder
3346
+ * factory (`{ Encoder }`) or a named `encoding`, or override
3347
+ * `createColumnFamilyStore` on a custom `Store`.
3348
+ *
3349
+ * @param name - The column family name.
3350
+ * @param options - Options for the column family, overriding inherited ones.
3351
+ * @returns A `RocksDatabase` bound to the column family.
3352
+ *
3353
+ * @example
3354
+ * ```typescript
3355
+ * const db = RocksDatabase.open('/path/to/database');
3356
+ * const events = db.use('events');
3357
+ * await events.put('e1', payload);
3358
+ * await db.put('k', 'v'); // default column family, unaffected
3359
+ * ```
3360
+ */
3361
+ use(name, options) {
3362
+ if (typeof name !== "string" || name === "") throw new TypeError("Column family name must be a non-empty string");
3363
+ if (name === this.#name) return this.open();
3364
+ const cached = this.#columnFamilies.get(name)?.deref();
3365
+ if (cached !== void 0 && cached.isOpen()) return cached;
3366
+ const columnFamily = new RocksDatabase(this.store.createColumnFamilyStore(name, options));
3367
+ columnFamily.open();
3368
+ this.#columnFamilies.set(name, new WeakRef(columnFamily));
3369
+ this.#columnFamilyRegistry.register(columnFamily, name);
3370
+ return columnFamily;
3371
+ }
3372
+ /**
3140
3373
  * Excecutes a function using a thread-safe lock to ensure mutual
3141
3374
  * exclusion.
3142
3375
  *
@@ -3443,11 +3676,12 @@ Object.defineProperty(TransactionLog.prototype, "query", { value({ start, end, e
3443
3676
  position += TRANSACTION_LOG_ENTRY_HEADER_SIZE;
3444
3677
  let matchesRange;
3445
3678
  if (foundExactStart) matchesRange = (!exclusiveStart || timestamp !== start) && timestamp < end;
3446
- else if (exactStart) if (timestamp === start) {
3447
- matchesRange = !exclusiveStart;
3448
- foundExactStart = true;
3449
- } else matchesRange = false;
3450
- else matchesRange = (exclusiveStart ? timestamp > start : timestamp >= start) && timestamp < end;
3679
+ else if (exactStart) {
3680
+ if (timestamp === start) {
3681
+ matchesRange = !exclusiveStart;
3682
+ foundExactStart = true;
3683
+ } else matchesRange = false;
3684
+ } else matchesRange = (exclusiveStart ? timestamp > start : timestamp >= start) && timestamp < end;
3451
3685
  const entryStart = position;
3452
3686
  position += length;
3453
3687
  if (matchesRange) return {
@@ -3530,9 +3764,9 @@ function loadLastPosition(transactionLog, readUncommitted) {
3530
3764
  //#region src/index.ts
3531
3765
  const versions = {
3532
3766
  rocksdb: version,
3533
- "rocksdb-js": "2.8.0"
3767
+ "rocksdb-js": "2.9.0"
3534
3768
  };
3535
3769
 
3536
3770
  //#endregion
3537
- export { BackgroundError, CorruptFrameError, CountEstimator, DBI, DBIterator, RocksDatabase, Store, Transaction, TransactionLog, backups, constants, coolTransactionLogs, currentThreadId, fileLockRelease, parseTransactionLog, registryStatus, shutdown, stats, supportedCompression, tryFileLock, validateTransactionLogStore, versions };
3771
+ export { BackgroundError, CorruptFrameError, CountEstimator, DBI, DBIterator, RocksDatabase, Store, Transaction, TransactionLog, backups, constants, coolTransactionLogs, currentThreadId, fileLockRelease, getWriteBufferManagerStats, parseTransactionLog, registryStatus, shutdown, stats, supportedCompression, tryFileLock, validateTransactionLogStore, versions };
3538
3772
  //# sourceMappingURL=index.mjs.map