qvdjs 0.9.1 → 0.9.3
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 +180 -35
- package/dist/index.cjs +156 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +155 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
1
2
|
import path from 'path';
|
|
2
|
-
import fs2 from 'fs';
|
|
3
3
|
import crypto from 'crypto';
|
|
4
4
|
import xml2 from 'xml2js';
|
|
5
5
|
import assert from 'assert';
|
|
@@ -250,8 +250,8 @@ var init_QvdSymbol = __esm({
|
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
252
|
});
|
|
253
|
-
function
|
|
254
|
-
const isCaseInsensitiveFS = process.platform === "win32"
|
|
253
|
+
function isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) {
|
|
254
|
+
const isCaseInsensitiveFS = process.platform === "win32";
|
|
255
255
|
const base = isCaseInsensitiveFS ? resolvedBaseDir.toLowerCase() : resolvedBaseDir;
|
|
256
256
|
const target = isCaseInsensitiveFS ? resolvedPath.toLowerCase() : resolvedPath;
|
|
257
257
|
const relative = path.relative(base, target);
|
|
@@ -263,6 +263,55 @@ function isWithinDirectory(resolvedBaseDir, resolvedPath) {
|
|
|
263
263
|
}
|
|
264
264
|
return relative !== ".." && !relative.startsWith(`..${path.sep}`);
|
|
265
265
|
}
|
|
266
|
+
function resolveDeepestExisting(target) {
|
|
267
|
+
let current = target;
|
|
268
|
+
for (; ; ) {
|
|
269
|
+
try {
|
|
270
|
+
return fs.realpathSync(current);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
const code = (
|
|
273
|
+
/** @type {{code?: string}} */
|
|
274
|
+
error?.code
|
|
275
|
+
);
|
|
276
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
const parent = path.dirname(current);
|
|
280
|
+
if (parent === current) {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
current = parent;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {
|
|
288
|
+
let baseStat;
|
|
289
|
+
try {
|
|
290
|
+
baseStat = fs.statSync(fs.realpathSync(resolvedBaseDir));
|
|
291
|
+
} catch {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
let current = resolveDeepestExisting(resolvedPath);
|
|
295
|
+
if (current === null) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
for (; ; ) {
|
|
299
|
+
let stat;
|
|
300
|
+
try {
|
|
301
|
+
stat = fs.statSync(current);
|
|
302
|
+
} catch {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
const parent = path.dirname(current);
|
|
309
|
+
if (parent === current) {
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
current = parent;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
266
315
|
function validatePath(filePath, allowedDir) {
|
|
267
316
|
if (typeof filePath !== "string" || filePath.length === 0) {
|
|
268
317
|
throw new QvdValidationError("filePath must be a non-empty string", {
|
|
@@ -285,12 +334,17 @@ function validatePath(filePath, allowedDir) {
|
|
|
285
334
|
const resolvedPath = path.resolve(filePath);
|
|
286
335
|
const baseDir = allowedDir || process.cwd();
|
|
287
336
|
const resolvedBaseDir = path.resolve(baseDir);
|
|
288
|
-
|
|
337
|
+
const onDisk = isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath);
|
|
338
|
+
const contained = onDisk === null ? isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) : onDisk;
|
|
339
|
+
if (!contained) {
|
|
289
340
|
throw new QvdSecurityError("Path traversal detected: Access denied", {
|
|
290
341
|
path: filePath,
|
|
291
342
|
resolvedPath,
|
|
292
343
|
allowedDir: resolvedBaseDir,
|
|
293
|
-
reason: "outside_allowed_directory"
|
|
344
|
+
reason: "outside_allowed_directory",
|
|
345
|
+
// Says which check refused, so a rejection of a path that looks contained is traceable to
|
|
346
|
+
// a symlink or a case difference rather than looking like a bug.
|
|
347
|
+
check: onDisk === null ? "lexical" : "filesystem"
|
|
294
348
|
});
|
|
295
349
|
}
|
|
296
350
|
return resolvedPath;
|
|
@@ -319,7 +373,8 @@ var init_QvdFileWriter = __esm({
|
|
|
319
373
|
* @param {QvdDataFrame} df The data frame to write to the QVD file.
|
|
320
374
|
* @param {Object} [options={}] Options for the writer.
|
|
321
375
|
* @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file
|
|
322
|
-
* path must be within this directory
|
|
376
|
+
* path must be within this directory, with symlinks resolved first, so a link inside it that
|
|
377
|
+
* points outside it is rejected. Defaults to the current working directory. To permit
|
|
323
378
|
* an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\' on Windows); a null or
|
|
324
379
|
* empty value falls back to the working directory rather than removing the restriction.
|
|
325
380
|
* @param {Function} [options.onProgress] Optional progress callback function.
|
|
@@ -367,7 +422,7 @@ var init_QvdFileWriter = __esm({
|
|
|
367
422
|
const headerBuffer = Buffer.concat([Buffer.from(this._header, "utf-8"), Buffer.from([0])]);
|
|
368
423
|
let fd;
|
|
369
424
|
try {
|
|
370
|
-
fd = await
|
|
425
|
+
fd = await fs.promises.open(this._path, "w");
|
|
371
426
|
await fd.write(headerBuffer, 0, headerBuffer.length, 0);
|
|
372
427
|
await fd.write(this._symbolBuffer, 0, this._symbolBuffer.length, headerBuffer.length);
|
|
373
428
|
await fd.write(this._indexBuffer, 0, this._indexBuffer.length, headerBuffer.length + this._symbolBuffer.length);
|
|
@@ -679,6 +734,28 @@ var init_bitUtils = __esm({
|
|
|
679
734
|
function getHeapLimit() {
|
|
680
735
|
return v8.getHeapStatistics().heap_size_limit;
|
|
681
736
|
}
|
|
737
|
+
function heapLimitIsMeaningful() {
|
|
738
|
+
return !process.versions.bun && !process.versions.deno;
|
|
739
|
+
}
|
|
740
|
+
function getMemoryBudget() {
|
|
741
|
+
const candidates = [];
|
|
742
|
+
if (heapLimitIsMeaningful()) {
|
|
743
|
+
candidates.push({ source: "V8 heap limit", bytes: getHeapLimit() });
|
|
744
|
+
}
|
|
745
|
+
const constrained = typeof process.constrainedMemory === "function" ? process.constrainedMemory() : 0;
|
|
746
|
+
if (constrained > 0 && constrained < os.totalmem()) {
|
|
747
|
+
candidates.push({ source: "container memory limit", bytes: constrained });
|
|
748
|
+
}
|
|
749
|
+
if (candidates.length === 0) {
|
|
750
|
+
candidates.push({ source: "total system memory", bytes: os.totalmem() });
|
|
751
|
+
}
|
|
752
|
+
const observed = [{ source: "free memory (os.freemem)", bytes: os.freemem() }];
|
|
753
|
+
if (typeof process.availableMemory === "function") {
|
|
754
|
+
observed.push({ source: "available memory", bytes: process.availableMemory() });
|
|
755
|
+
}
|
|
756
|
+
const binding = candidates.reduce((lowest, candidate) => candidate.bytes < lowest.bytes ? candidate : lowest);
|
|
757
|
+
return { bytes: binding.bytes, limitedBy: binding.source, candidates, observed };
|
|
758
|
+
}
|
|
682
759
|
function estimateMemoryUsage(symbolTableSize, maxRows, totalRows) {
|
|
683
760
|
const FULL_PARSE_OVERHEAD = 6;
|
|
684
761
|
const MINIMAL_OVERHEAD = 0.01;
|
|
@@ -695,11 +772,14 @@ function validateMemoryAvailability(symbolTableSize, maxRows, totalRows, filePat
|
|
|
695
772
|
if (typeof safetyFactor !== "number" || safetyFactor < 0 || safetyFactor > 1) {
|
|
696
773
|
throw new QvdValidationError("safetyFactor must be a number between 0.0 and 1.0", { safetyFactor });
|
|
697
774
|
}
|
|
698
|
-
|
|
775
|
+
if (safetyFactor === 0) {
|
|
776
|
+
return;
|
|
777
|
+
}
|
|
778
|
+
const budget = getMemoryBudget();
|
|
699
779
|
const heapLimit = getHeapLimit();
|
|
780
|
+
const availableMemory = budget.bytes;
|
|
700
781
|
const estimatedMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows);
|
|
701
|
-
const
|
|
702
|
-
const maxAllowedMemory = effectiveLimit * safetyFactor;
|
|
782
|
+
const maxAllowedMemory = budget.bytes * safetyFactor;
|
|
703
783
|
if (estimatedMemory > maxAllowedMemory) {
|
|
704
784
|
const safeSymbolPercentage = maxAllowedMemory / (symbolTableSize * 6);
|
|
705
785
|
const safeRowPercentage = Math.pow(safeSymbolPercentage, 2);
|
|
@@ -709,9 +789,12 @@ function validateMemoryAvailability(symbolTableSize, maxRows, totalRows, filePat
|
|
|
709
789
|
const availableMB = Math.round(maxAllowedMemory / 1024 / 1024);
|
|
710
790
|
const heapLimitMB = Math.round(heapLimit / 1024 / 1024);
|
|
711
791
|
const availableRamMB = Math.round(availableMemory / 1024 / 1024);
|
|
712
|
-
const limitingFactor =
|
|
792
|
+
const limitingFactor = budget.limitedBy;
|
|
793
|
+
const budgetBreakdown = budget.candidates.map((candidate) => `${candidate.source} ${Math.round(candidate.bytes / 1024 / 1024)}MB`).join(", ");
|
|
794
|
+
const observedBreakdown = budget.observed.map((entry) => `${entry.source} ${Math.round(entry.bytes / 1024 / 1024)}MB`).join(", ");
|
|
795
|
+
const advice = limitingFactor === "container memory limit" ? `The binding limit is the container's, so raising --max-old-space-size would let V8 grow past it and be killed by the OOM killer instead. Set it below the container limit, raise the limit, or load fewer rows with maxRows (recommended: ${recommendedMaxRows.toLocaleString()} rows or less).` : `Try loading fewer rows using the maxRows parameter (recommended: ${recommendedMaxRows.toLocaleString()} rows or less), or raise the heap with --max-old-space-size.`;
|
|
713
796
|
throw new QvdValidationError(
|
|
714
|
-
`Insufficient memory to load file safely. Symbol table: ${sizeMB}MB, Estimated memory needed: ${estimatedMB}MB, Available: ${availableMB}MB (limited by ${limitingFactor}: ${
|
|
797
|
+
`Insufficient memory to load file safely. Symbol table: ${sizeMB}MB, Estimated memory needed: ${estimatedMB}MB, Available: ${availableMB}MB (limited by ${limitingFactor}; considered: ${budgetBreakdown}; observed but not used: ${observedBreakdown}). ` + advice,
|
|
715
798
|
{
|
|
716
799
|
file: filePath,
|
|
717
800
|
symbolTableSize,
|
|
@@ -721,6 +804,8 @@ function validateMemoryAvailability(symbolTableSize, maxRows, totalRows, filePat
|
|
|
721
804
|
heapLimitMB,
|
|
722
805
|
availableRamMB,
|
|
723
806
|
limitingFactor,
|
|
807
|
+
memoryBudget: budget.candidates,
|
|
808
|
+
memoryObserved: budget.observed,
|
|
724
809
|
totalRows,
|
|
725
810
|
maxRows,
|
|
726
811
|
recommendedMaxRows
|
|
@@ -1230,17 +1315,26 @@ var init_QvdFileReader = __esm({
|
|
|
1230
1315
|
* @param {string} filePath The path to the QVD file to load.
|
|
1231
1316
|
* @param {Object} [options={}] Options for the reader.
|
|
1232
1317
|
* @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file
|
|
1233
|
-
* path must be within this directory
|
|
1318
|
+
* path must be within this directory, with symlinks resolved first, so a link inside it that
|
|
1319
|
+
* points outside it is rejected. Defaults to the current working directory. To permit
|
|
1234
1320
|
* an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\' on Windows); a null or
|
|
1235
1321
|
* empty value falls back to the working directory rather than removing the restriction.
|
|
1236
|
-
* @param {number} [options.memorySafetyFactor=0.3]
|
|
1237
|
-
*
|
|
1238
|
-
*
|
|
1322
|
+
* @param {number} [options.memorySafetyFactor=0.3] Fraction (0.0-1.0) of the memory budget a
|
|
1323
|
+
* load may use. The budget is the smallest of the V8 heap limit, any container memory limit,
|
|
1324
|
+
* and the memory the OS reports as available. Default is 0.3. **Zero disables the memory
|
|
1325
|
+
* check entirely**, which is the escape hatch for runtimes whose limits cannot be measured -
|
|
1326
|
+
* Bun reports its current heap as its heap limit - and for callers who would rather manage
|
|
1327
|
+
* memory themselves than trust the estimate.
|
|
1328
|
+
* @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes,
|
|
1329
|
+
* above which a lazy load switches to the two-pass filtering path. The default of 50MB is
|
|
1330
|
+
* the point where the extra analysis pass pays for itself; lower it to use filtering on
|
|
1331
|
+
* smaller files, raise it to keep the simpler single-pass read for longer.
|
|
1239
1332
|
*/
|
|
1240
1333
|
constructor(filePath, options = {}) {
|
|
1241
|
-
const { allowedDir, memorySafetyFactor = 0.3 } = options;
|
|
1334
|
+
const { allowedDir, memorySafetyFactor = 0.3, symbolFilteringThreshold = 50 * 1024 * 1024 } = options;
|
|
1242
1335
|
this._path = validatePath(filePath, allowedDir);
|
|
1243
1336
|
this._memorySafetyFactor = memorySafetyFactor;
|
|
1337
|
+
this._symbolFilteringThreshold = symbolFilteringThreshold;
|
|
1244
1338
|
this._buffer = null;
|
|
1245
1339
|
this._headerOffset = null;
|
|
1246
1340
|
this._symbolTableOffset = null;
|
|
@@ -1279,13 +1373,13 @@ var init_QvdFileReader = __esm({
|
|
|
1279
1373
|
*/
|
|
1280
1374
|
async _readData(maxRows = null) {
|
|
1281
1375
|
if (maxRows === null) {
|
|
1282
|
-
this._buffer = await
|
|
1376
|
+
this._buffer = await fs.promises.readFile(this._path);
|
|
1283
1377
|
this._fileSize = this._buffer.length;
|
|
1284
1378
|
return;
|
|
1285
1379
|
}
|
|
1286
1380
|
const HEADER_DELIMITER = "\r\n\0";
|
|
1287
1381
|
const CHUNK_SIZE = 64 * 1024;
|
|
1288
|
-
const stream =
|
|
1382
|
+
const stream = fs.createReadStream(this._path, {
|
|
1289
1383
|
highWaterMark: CHUNK_SIZE
|
|
1290
1384
|
});
|
|
1291
1385
|
const headerChunks = [];
|
|
@@ -1368,7 +1462,7 @@ var init_QvdFileReader = __esm({
|
|
|
1368
1462
|
}
|
|
1369
1463
|
const indexTableBytesToRead = rowsToLoad * recordSize;
|
|
1370
1464
|
const totalBytesToRead = indexTableOffset + indexTableBytesToRead;
|
|
1371
|
-
const fd = await
|
|
1465
|
+
const fd = await fs.promises.open(this._path, "r");
|
|
1372
1466
|
try {
|
|
1373
1467
|
const { size: fileSize } = await fd.stat();
|
|
1374
1468
|
this._fileSize = fileSize;
|
|
@@ -1672,15 +1766,12 @@ var init_QvdFileReader = __esm({
|
|
|
1672
1766
|
await this._readData(maxRows);
|
|
1673
1767
|
await this._parseHeader();
|
|
1674
1768
|
let symbolsToKeep = null;
|
|
1769
|
+
let symbolsKept = null;
|
|
1675
1770
|
if (maxRows !== null && this._header) {
|
|
1676
1771
|
const symbolTableLength = parseInt(this._header["QvdTableHeader"]["Offset"], 10);
|
|
1677
|
-
|
|
1678
|
-
if (symbolTableLength > SYMBOL_FILTERING_THRESHOLD) {
|
|
1772
|
+
if (symbolTableLength > this._symbolFilteringThreshold) {
|
|
1679
1773
|
symbolsToKeep = await this._analyzeIndexTableSymbolUsage(maxRows);
|
|
1680
|
-
|
|
1681
|
-
console.log(
|
|
1682
|
-
`[Phase 2.5 Optimization] Using stream-and-skip parsing: keeping ${totalSymbols} symbols from ${(symbolTableLength / 1024 / 1024).toFixed(1)}MB symbol table`
|
|
1683
|
-
);
|
|
1774
|
+
symbolsKept = Array.from(symbolsToKeep.values()).reduce((sum, set) => sum + set.size, 0);
|
|
1684
1775
|
}
|
|
1685
1776
|
}
|
|
1686
1777
|
await this._parseSymbolTable(symbolsToKeep, maxRows);
|
|
@@ -1717,7 +1808,14 @@ var init_QvdFileReader = __esm({
|
|
|
1717
1808
|
const columns = fields.map((field) => field["FieldName"]);
|
|
1718
1809
|
const data = this._indexTable.map((_, index) => getRow(index));
|
|
1719
1810
|
const metadata = this._header["QvdTableHeader"];
|
|
1720
|
-
|
|
1811
|
+
const loadStats = {
|
|
1812
|
+
symbolTableBytes: parseInt(this._header["QvdTableHeader"]["Offset"], 10),
|
|
1813
|
+
totalRows: parseInt(this._header["QvdTableHeader"]["NoOfRecords"], 10),
|
|
1814
|
+
rowsLoaded: data.length,
|
|
1815
|
+
symbolFiltering: symbolsToKeep !== null,
|
|
1816
|
+
symbolsKept
|
|
1817
|
+
};
|
|
1818
|
+
return new QvdDataFrame(data, columns, metadata, loadStats);
|
|
1721
1819
|
}
|
|
1722
1820
|
};
|
|
1723
1821
|
}
|
|
@@ -1734,11 +1832,13 @@ var init_QvdDataFrame = __esm({
|
|
|
1734
1832
|
* @param {Array<Array<any>>} data The data of the data frame.
|
|
1735
1833
|
* @param {Array<string>} columns The columns of the data frame.
|
|
1736
1834
|
* @param {QvdMetadata|null} metadata The metadata from the QVD file header (optional).
|
|
1835
|
+
* @param {QvdLoadStats|null} loadStats Statistics about the read (optional).
|
|
1737
1836
|
*/
|
|
1738
|
-
constructor(data, columns, metadata = null) {
|
|
1837
|
+
constructor(data, columns, metadata = null, loadStats = null) {
|
|
1739
1838
|
this._data = data;
|
|
1740
1839
|
this._columns = columns;
|
|
1741
1840
|
this._metadata = metadata;
|
|
1841
|
+
this._loadStats = loadStats;
|
|
1742
1842
|
}
|
|
1743
1843
|
/**
|
|
1744
1844
|
* Returns the data of the data frame.
|
|
@@ -1765,6 +1865,21 @@ var init_QvdDataFrame = __esm({
|
|
|
1765
1865
|
get metadata() {
|
|
1766
1866
|
return this._metadata;
|
|
1767
1867
|
}
|
|
1868
|
+
/**
|
|
1869
|
+
* Returns statistics about the read that produced this data frame.
|
|
1870
|
+
*
|
|
1871
|
+
* Only a frame returned by fromQvd() carries these; fromDict(), head() and tail() produce
|
|
1872
|
+
* frames that describe no particular read, and report null rather than a stale figure.
|
|
1873
|
+
*
|
|
1874
|
+
* The main use is confirming that a lazy load actually filtered the symbol table:
|
|
1875
|
+
* `symbolFiltering` says whether the two-pass path ran, and `symbolsKept` how many symbols
|
|
1876
|
+
* survived it, which for a small maxRows should be a tiny fraction of the file's total.
|
|
1877
|
+
*
|
|
1878
|
+
* @return {QvdLoadStats|null} Load statistics, or null if this frame did not come from a file.
|
|
1879
|
+
*/
|
|
1880
|
+
get loadStats() {
|
|
1881
|
+
return this._loadStats;
|
|
1882
|
+
}
|
|
1768
1883
|
/**
|
|
1769
1884
|
* Returns file-level metadata from the QVD header.
|
|
1770
1885
|
* @return {Object} File-level metadata properties.
|
|
@@ -2114,7 +2229,8 @@ var init_QvdDataFrame = __esm({
|
|
|
2114
2229
|
* @param {string} path The path to the QVD file.
|
|
2115
2230
|
* @param {Object} [options] Optional writing options.
|
|
2116
2231
|
* @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path
|
|
2117
|
-
* must be within this directory
|
|
2232
|
+
* must be within this directory, with symlinks resolved first, so a link inside it that points
|
|
2233
|
+
* outside it is rejected. Defaults to the current working directory. To permit an entire
|
|
2118
2234
|
* volume, pass its root explicitly ('/' on POSIX, 'C:\\' on Windows); a null or empty value falls
|
|
2119
2235
|
* back to the working directory rather than removing the restriction.
|
|
2120
2236
|
* @param {Function} [options.onProgress] Optional progress callback function that receives progress updates during write operations.
|
|
@@ -2135,12 +2251,16 @@ var init_QvdDataFrame = __esm({
|
|
|
2135
2251
|
* @param {number|null} [options.maxRows] The maximum number of rows to load. Must be a non-negative
|
|
2136
2252
|
* integer; if not specified or null, all rows are loaded. Anything else throws a QvdValidationError.
|
|
2137
2253
|
* @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path
|
|
2138
|
-
* must be within this directory
|
|
2254
|
+
* must be within this directory, with symlinks resolved first, so a link inside it that points
|
|
2255
|
+
* outside it is rejected. Defaults to the current working directory. To permit an entire
|
|
2139
2256
|
* volume, pass its root explicitly ('/' on POSIX, 'C:\\' on Windows); a null or empty value falls
|
|
2140
2257
|
* back to the working directory rather than removing the restriction.
|
|
2141
|
-
* @param {number} [options.memorySafetyFactor=0.3]
|
|
2142
|
-
*
|
|
2143
|
-
*
|
|
2258
|
+
* @param {number} [options.memorySafetyFactor=0.3] Fraction (0.0-1.0) of the memory budget a load
|
|
2259
|
+
* may use. The budget is the smallest of the V8 heap limit, any container memory limit, and the
|
|
2260
|
+
* memory the OS reports as available. Default is 0.3; raise it when running with a larger heap via
|
|
2261
|
+
* --max-old-space-size. **Zero disables the memory check entirely.**
|
|
2262
|
+
* @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes, above which
|
|
2263
|
+
* a lazy load switches to the two-pass filtering path. Defaults to 50MB.
|
|
2144
2264
|
* @throws {QvdValidationError} If options.maxRows is neither null/undefined nor a non-negative integer.
|
|
2145
2265
|
* @return {Promise<QvdDataFrame>} The data frame of the QVD file.
|
|
2146
2266
|
*/
|
|
@@ -2148,7 +2268,8 @@ var init_QvdDataFrame = __esm({
|
|
|
2148
2268
|
const { QvdFileReader: QvdFileReader2 } = await Promise.resolve().then(() => (init_QvdFileReader(), QvdFileReader_exports));
|
|
2149
2269
|
const readerOptions = {
|
|
2150
2270
|
allowedDir: options.allowedDir,
|
|
2151
|
-
memorySafetyFactor: options.memorySafetyFactor
|
|
2271
|
+
memorySafetyFactor: options.memorySafetyFactor,
|
|
2272
|
+
symbolFilteringThreshold: options.symbolFilteringThreshold
|
|
2152
2273
|
};
|
|
2153
2274
|
return await new QvdFileReader2(path3, readerOptions).load(options.maxRows !== void 0 ? options.maxRows : null);
|
|
2154
2275
|
}
|