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.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var fs = require('fs');
|
|
3
4
|
var path = require('path');
|
|
4
|
-
var fs2 = require('fs');
|
|
5
5
|
var crypto = require('crypto');
|
|
6
6
|
var xml2 = require('xml2js');
|
|
7
7
|
var assert = require('assert');
|
|
@@ -10,8 +10,8 @@ var v8 = require('v8');
|
|
|
10
10
|
|
|
11
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
12
|
|
|
13
|
+
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
13
14
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
14
|
-
var fs2__default = /*#__PURE__*/_interopDefault(fs2);
|
|
15
15
|
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
16
16
|
var xml2__default = /*#__PURE__*/_interopDefault(xml2);
|
|
17
17
|
var assert__default = /*#__PURE__*/_interopDefault(assert);
|
|
@@ -262,8 +262,8 @@ var init_QvdSymbol = __esm({
|
|
|
262
262
|
};
|
|
263
263
|
}
|
|
264
264
|
});
|
|
265
|
-
function
|
|
266
|
-
const isCaseInsensitiveFS = process.platform === "win32"
|
|
265
|
+
function isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) {
|
|
266
|
+
const isCaseInsensitiveFS = process.platform === "win32";
|
|
267
267
|
const base = isCaseInsensitiveFS ? resolvedBaseDir.toLowerCase() : resolvedBaseDir;
|
|
268
268
|
const target = isCaseInsensitiveFS ? resolvedPath.toLowerCase() : resolvedPath;
|
|
269
269
|
const relative = path__default.default.relative(base, target);
|
|
@@ -275,6 +275,55 @@ function isWithinDirectory(resolvedBaseDir, resolvedPath) {
|
|
|
275
275
|
}
|
|
276
276
|
return relative !== ".." && !relative.startsWith(`..${path__default.default.sep}`);
|
|
277
277
|
}
|
|
278
|
+
function resolveDeepestExisting(target) {
|
|
279
|
+
let current = target;
|
|
280
|
+
for (; ; ) {
|
|
281
|
+
try {
|
|
282
|
+
return fs__default.default.realpathSync(current);
|
|
283
|
+
} catch (error) {
|
|
284
|
+
const code = (
|
|
285
|
+
/** @type {{code?: string}} */
|
|
286
|
+
error?.code
|
|
287
|
+
);
|
|
288
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const parent = path__default.default.dirname(current);
|
|
292
|
+
if (parent === current) {
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
current = parent;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
function isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath) {
|
|
300
|
+
let baseStat;
|
|
301
|
+
try {
|
|
302
|
+
baseStat = fs__default.default.statSync(fs__default.default.realpathSync(resolvedBaseDir));
|
|
303
|
+
} catch {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
let current = resolveDeepestExisting(resolvedPath);
|
|
307
|
+
if (current === null) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
for (; ; ) {
|
|
311
|
+
let stat;
|
|
312
|
+
try {
|
|
313
|
+
stat = fs__default.default.statSync(current);
|
|
314
|
+
} catch {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
if (stat.dev === baseStat.dev && stat.ino === baseStat.ino) {
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
const parent = path__default.default.dirname(current);
|
|
321
|
+
if (parent === current) {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
current = parent;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
278
327
|
function validatePath(filePath, allowedDir) {
|
|
279
328
|
if (typeof filePath !== "string" || filePath.length === 0) {
|
|
280
329
|
throw new exports.QvdValidationError("filePath must be a non-empty string", {
|
|
@@ -297,12 +346,17 @@ function validatePath(filePath, allowedDir) {
|
|
|
297
346
|
const resolvedPath = path__default.default.resolve(filePath);
|
|
298
347
|
const baseDir = allowedDir || process.cwd();
|
|
299
348
|
const resolvedBaseDir = path__default.default.resolve(baseDir);
|
|
300
|
-
|
|
349
|
+
const onDisk = isWithinDirectoryOnDisk(resolvedBaseDir, resolvedPath);
|
|
350
|
+
const contained = onDisk === null ? isWithinDirectoryLexically(resolvedBaseDir, resolvedPath) : onDisk;
|
|
351
|
+
if (!contained) {
|
|
301
352
|
throw new exports.QvdSecurityError("Path traversal detected: Access denied", {
|
|
302
353
|
path: filePath,
|
|
303
354
|
resolvedPath,
|
|
304
355
|
allowedDir: resolvedBaseDir,
|
|
305
|
-
reason: "outside_allowed_directory"
|
|
356
|
+
reason: "outside_allowed_directory",
|
|
357
|
+
// Says which check refused, so a rejection of a path that looks contained is traceable to
|
|
358
|
+
// a symlink or a case difference rather than looking like a bug.
|
|
359
|
+
check: onDisk === null ? "lexical" : "filesystem"
|
|
306
360
|
});
|
|
307
361
|
}
|
|
308
362
|
return resolvedPath;
|
|
@@ -331,7 +385,8 @@ var init_QvdFileWriter = __esm({
|
|
|
331
385
|
* @param {QvdDataFrame} df The data frame to write to the QVD file.
|
|
332
386
|
* @param {Object} [options={}] Options for the writer.
|
|
333
387
|
* @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file
|
|
334
|
-
* path must be within this directory
|
|
388
|
+
* path must be within this directory, with symlinks resolved first, so a link inside it that
|
|
389
|
+
* points outside it is rejected. Defaults to the current working directory. To permit
|
|
335
390
|
* an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\' on Windows); a null or
|
|
336
391
|
* empty value falls back to the working directory rather than removing the restriction.
|
|
337
392
|
* @param {Function} [options.onProgress] Optional progress callback function.
|
|
@@ -379,7 +434,7 @@ var init_QvdFileWriter = __esm({
|
|
|
379
434
|
const headerBuffer = Buffer.concat([Buffer.from(this._header, "utf-8"), Buffer.from([0])]);
|
|
380
435
|
let fd;
|
|
381
436
|
try {
|
|
382
|
-
fd = await
|
|
437
|
+
fd = await fs__default.default.promises.open(this._path, "w");
|
|
383
438
|
await fd.write(headerBuffer, 0, headerBuffer.length, 0);
|
|
384
439
|
await fd.write(this._symbolBuffer, 0, this._symbolBuffer.length, headerBuffer.length);
|
|
385
440
|
await fd.write(this._indexBuffer, 0, this._indexBuffer.length, headerBuffer.length + this._symbolBuffer.length);
|
|
@@ -691,6 +746,28 @@ var init_bitUtils = __esm({
|
|
|
691
746
|
function getHeapLimit() {
|
|
692
747
|
return v8__default.default.getHeapStatistics().heap_size_limit;
|
|
693
748
|
}
|
|
749
|
+
function heapLimitIsMeaningful() {
|
|
750
|
+
return !process.versions.bun && !process.versions.deno;
|
|
751
|
+
}
|
|
752
|
+
function getMemoryBudget() {
|
|
753
|
+
const candidates = [];
|
|
754
|
+
if (heapLimitIsMeaningful()) {
|
|
755
|
+
candidates.push({ source: "V8 heap limit", bytes: getHeapLimit() });
|
|
756
|
+
}
|
|
757
|
+
const constrained = typeof process.constrainedMemory === "function" ? process.constrainedMemory() : 0;
|
|
758
|
+
if (constrained > 0 && constrained < os__default.default.totalmem()) {
|
|
759
|
+
candidates.push({ source: "container memory limit", bytes: constrained });
|
|
760
|
+
}
|
|
761
|
+
if (candidates.length === 0) {
|
|
762
|
+
candidates.push({ source: "total system memory", bytes: os__default.default.totalmem() });
|
|
763
|
+
}
|
|
764
|
+
const observed = [{ source: "free memory (os.freemem)", bytes: os__default.default.freemem() }];
|
|
765
|
+
if (typeof process.availableMemory === "function") {
|
|
766
|
+
observed.push({ source: "available memory", bytes: process.availableMemory() });
|
|
767
|
+
}
|
|
768
|
+
const binding = candidates.reduce((lowest, candidate) => candidate.bytes < lowest.bytes ? candidate : lowest);
|
|
769
|
+
return { bytes: binding.bytes, limitedBy: binding.source, candidates, observed };
|
|
770
|
+
}
|
|
694
771
|
function estimateMemoryUsage(symbolTableSize, maxRows, totalRows) {
|
|
695
772
|
const FULL_PARSE_OVERHEAD = 6;
|
|
696
773
|
const MINIMAL_OVERHEAD = 0.01;
|
|
@@ -707,11 +784,14 @@ function validateMemoryAvailability(symbolTableSize, maxRows, totalRows, filePat
|
|
|
707
784
|
if (typeof safetyFactor !== "number" || safetyFactor < 0 || safetyFactor > 1) {
|
|
708
785
|
throw new exports.QvdValidationError("safetyFactor must be a number between 0.0 and 1.0", { safetyFactor });
|
|
709
786
|
}
|
|
710
|
-
|
|
787
|
+
if (safetyFactor === 0) {
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
const budget = getMemoryBudget();
|
|
711
791
|
const heapLimit = getHeapLimit();
|
|
792
|
+
const availableMemory = budget.bytes;
|
|
712
793
|
const estimatedMemory = estimateMemoryUsage(symbolTableSize, maxRows, totalRows);
|
|
713
|
-
const
|
|
714
|
-
const maxAllowedMemory = effectiveLimit * safetyFactor;
|
|
794
|
+
const maxAllowedMemory = budget.bytes * safetyFactor;
|
|
715
795
|
if (estimatedMemory > maxAllowedMemory) {
|
|
716
796
|
const safeSymbolPercentage = maxAllowedMemory / (symbolTableSize * 6);
|
|
717
797
|
const safeRowPercentage = Math.pow(safeSymbolPercentage, 2);
|
|
@@ -721,9 +801,12 @@ function validateMemoryAvailability(symbolTableSize, maxRows, totalRows, filePat
|
|
|
721
801
|
const availableMB = Math.round(maxAllowedMemory / 1024 / 1024);
|
|
722
802
|
const heapLimitMB = Math.round(heapLimit / 1024 / 1024);
|
|
723
803
|
const availableRamMB = Math.round(availableMemory / 1024 / 1024);
|
|
724
|
-
const limitingFactor =
|
|
804
|
+
const limitingFactor = budget.limitedBy;
|
|
805
|
+
const budgetBreakdown = budget.candidates.map((candidate) => `${candidate.source} ${Math.round(candidate.bytes / 1024 / 1024)}MB`).join(", ");
|
|
806
|
+
const observedBreakdown = budget.observed.map((entry) => `${entry.source} ${Math.round(entry.bytes / 1024 / 1024)}MB`).join(", ");
|
|
807
|
+
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.`;
|
|
725
808
|
throw new exports.QvdValidationError(
|
|
726
|
-
`Insufficient memory to load file safely. Symbol table: ${sizeMB}MB, Estimated memory needed: ${estimatedMB}MB, Available: ${availableMB}MB (limited by ${limitingFactor}: ${
|
|
809
|
+
`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,
|
|
727
810
|
{
|
|
728
811
|
file: filePath,
|
|
729
812
|
symbolTableSize,
|
|
@@ -733,6 +816,8 @@ function validateMemoryAvailability(symbolTableSize, maxRows, totalRows, filePat
|
|
|
733
816
|
heapLimitMB,
|
|
734
817
|
availableRamMB,
|
|
735
818
|
limitingFactor,
|
|
819
|
+
memoryBudget: budget.candidates,
|
|
820
|
+
memoryObserved: budget.observed,
|
|
736
821
|
totalRows,
|
|
737
822
|
maxRows,
|
|
738
823
|
recommendedMaxRows
|
|
@@ -1242,17 +1327,26 @@ var init_QvdFileReader = __esm({
|
|
|
1242
1327
|
* @param {string} filePath The path to the QVD file to load.
|
|
1243
1328
|
* @param {Object} [options={}] Options for the reader.
|
|
1244
1329
|
* @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file
|
|
1245
|
-
* path must be within this directory
|
|
1330
|
+
* path must be within this directory, with symlinks resolved first, so a link inside it that
|
|
1331
|
+
* points outside it is rejected. Defaults to the current working directory. To permit
|
|
1246
1332
|
* an entire volume, pass its root explicitly ('/' on POSIX, 'C:\\' on Windows); a null or
|
|
1247
1333
|
* empty value falls back to the working directory rather than removing the restriction.
|
|
1248
|
-
* @param {number} [options.memorySafetyFactor=0.3]
|
|
1249
|
-
*
|
|
1250
|
-
*
|
|
1334
|
+
* @param {number} [options.memorySafetyFactor=0.3] Fraction (0.0-1.0) of the memory budget a
|
|
1335
|
+
* load may use. The budget is the smallest of the V8 heap limit, any container memory limit,
|
|
1336
|
+
* and the memory the OS reports as available. Default is 0.3. **Zero disables the memory
|
|
1337
|
+
* check entirely**, which is the escape hatch for runtimes whose limits cannot be measured -
|
|
1338
|
+
* Bun reports its current heap as its heap limit - and for callers who would rather manage
|
|
1339
|
+
* memory themselves than trust the estimate.
|
|
1340
|
+
* @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes,
|
|
1341
|
+
* above which a lazy load switches to the two-pass filtering path. The default of 50MB is
|
|
1342
|
+
* the point where the extra analysis pass pays for itself; lower it to use filtering on
|
|
1343
|
+
* smaller files, raise it to keep the simpler single-pass read for longer.
|
|
1251
1344
|
*/
|
|
1252
1345
|
constructor(filePath, options = {}) {
|
|
1253
|
-
const { allowedDir, memorySafetyFactor = 0.3 } = options;
|
|
1346
|
+
const { allowedDir, memorySafetyFactor = 0.3, symbolFilteringThreshold = 50 * 1024 * 1024 } = options;
|
|
1254
1347
|
this._path = validatePath(filePath, allowedDir);
|
|
1255
1348
|
this._memorySafetyFactor = memorySafetyFactor;
|
|
1349
|
+
this._symbolFilteringThreshold = symbolFilteringThreshold;
|
|
1256
1350
|
this._buffer = null;
|
|
1257
1351
|
this._headerOffset = null;
|
|
1258
1352
|
this._symbolTableOffset = null;
|
|
@@ -1291,13 +1385,13 @@ var init_QvdFileReader = __esm({
|
|
|
1291
1385
|
*/
|
|
1292
1386
|
async _readData(maxRows = null) {
|
|
1293
1387
|
if (maxRows === null) {
|
|
1294
|
-
this._buffer = await
|
|
1388
|
+
this._buffer = await fs__default.default.promises.readFile(this._path);
|
|
1295
1389
|
this._fileSize = this._buffer.length;
|
|
1296
1390
|
return;
|
|
1297
1391
|
}
|
|
1298
1392
|
const HEADER_DELIMITER = "\r\n\0";
|
|
1299
1393
|
const CHUNK_SIZE = 64 * 1024;
|
|
1300
|
-
const stream =
|
|
1394
|
+
const stream = fs__default.default.createReadStream(this._path, {
|
|
1301
1395
|
highWaterMark: CHUNK_SIZE
|
|
1302
1396
|
});
|
|
1303
1397
|
const headerChunks = [];
|
|
@@ -1380,7 +1474,7 @@ var init_QvdFileReader = __esm({
|
|
|
1380
1474
|
}
|
|
1381
1475
|
const indexTableBytesToRead = rowsToLoad * recordSize;
|
|
1382
1476
|
const totalBytesToRead = indexTableOffset + indexTableBytesToRead;
|
|
1383
|
-
const fd = await
|
|
1477
|
+
const fd = await fs__default.default.promises.open(this._path, "r");
|
|
1384
1478
|
try {
|
|
1385
1479
|
const { size: fileSize } = await fd.stat();
|
|
1386
1480
|
this._fileSize = fileSize;
|
|
@@ -1684,15 +1778,12 @@ var init_QvdFileReader = __esm({
|
|
|
1684
1778
|
await this._readData(maxRows);
|
|
1685
1779
|
await this._parseHeader();
|
|
1686
1780
|
let symbolsToKeep = null;
|
|
1781
|
+
let symbolsKept = null;
|
|
1687
1782
|
if (maxRows !== null && this._header) {
|
|
1688
1783
|
const symbolTableLength = parseInt(this._header["QvdTableHeader"]["Offset"], 10);
|
|
1689
|
-
|
|
1690
|
-
if (symbolTableLength > SYMBOL_FILTERING_THRESHOLD) {
|
|
1784
|
+
if (symbolTableLength > this._symbolFilteringThreshold) {
|
|
1691
1785
|
symbolsToKeep = await this._analyzeIndexTableSymbolUsage(maxRows);
|
|
1692
|
-
|
|
1693
|
-
console.log(
|
|
1694
|
-
`[Phase 2.5 Optimization] Using stream-and-skip parsing: keeping ${totalSymbols} symbols from ${(symbolTableLength / 1024 / 1024).toFixed(1)}MB symbol table`
|
|
1695
|
-
);
|
|
1786
|
+
symbolsKept = Array.from(symbolsToKeep.values()).reduce((sum, set) => sum + set.size, 0);
|
|
1696
1787
|
}
|
|
1697
1788
|
}
|
|
1698
1789
|
await this._parseSymbolTable(symbolsToKeep, maxRows);
|
|
@@ -1729,7 +1820,14 @@ var init_QvdFileReader = __esm({
|
|
|
1729
1820
|
const columns = fields.map((field) => field["FieldName"]);
|
|
1730
1821
|
const data = this._indexTable.map((_, index) => getRow(index));
|
|
1731
1822
|
const metadata = this._header["QvdTableHeader"];
|
|
1732
|
-
|
|
1823
|
+
const loadStats = {
|
|
1824
|
+
symbolTableBytes: parseInt(this._header["QvdTableHeader"]["Offset"], 10),
|
|
1825
|
+
totalRows: parseInt(this._header["QvdTableHeader"]["NoOfRecords"], 10),
|
|
1826
|
+
rowsLoaded: data.length,
|
|
1827
|
+
symbolFiltering: symbolsToKeep !== null,
|
|
1828
|
+
symbolsKept
|
|
1829
|
+
};
|
|
1830
|
+
return new exports.QvdDataFrame(data, columns, metadata, loadStats);
|
|
1733
1831
|
}
|
|
1734
1832
|
};
|
|
1735
1833
|
}
|
|
@@ -1746,11 +1844,13 @@ var init_QvdDataFrame = __esm({
|
|
|
1746
1844
|
* @param {Array<Array<any>>} data The data of the data frame.
|
|
1747
1845
|
* @param {Array<string>} columns The columns of the data frame.
|
|
1748
1846
|
* @param {QvdMetadata|null} metadata The metadata from the QVD file header (optional).
|
|
1847
|
+
* @param {QvdLoadStats|null} loadStats Statistics about the read (optional).
|
|
1749
1848
|
*/
|
|
1750
|
-
constructor(data, columns, metadata = null) {
|
|
1849
|
+
constructor(data, columns, metadata = null, loadStats = null) {
|
|
1751
1850
|
this._data = data;
|
|
1752
1851
|
this._columns = columns;
|
|
1753
1852
|
this._metadata = metadata;
|
|
1853
|
+
this._loadStats = loadStats;
|
|
1754
1854
|
}
|
|
1755
1855
|
/**
|
|
1756
1856
|
* Returns the data of the data frame.
|
|
@@ -1777,6 +1877,21 @@ var init_QvdDataFrame = __esm({
|
|
|
1777
1877
|
get metadata() {
|
|
1778
1878
|
return this._metadata;
|
|
1779
1879
|
}
|
|
1880
|
+
/**
|
|
1881
|
+
* Returns statistics about the read that produced this data frame.
|
|
1882
|
+
*
|
|
1883
|
+
* Only a frame returned by fromQvd() carries these; fromDict(), head() and tail() produce
|
|
1884
|
+
* frames that describe no particular read, and report null rather than a stale figure.
|
|
1885
|
+
*
|
|
1886
|
+
* The main use is confirming that a lazy load actually filtered the symbol table:
|
|
1887
|
+
* `symbolFiltering` says whether the two-pass path ran, and `symbolsKept` how many symbols
|
|
1888
|
+
* survived it, which for a small maxRows should be a tiny fraction of the file's total.
|
|
1889
|
+
*
|
|
1890
|
+
* @return {QvdLoadStats|null} Load statistics, or null if this frame did not come from a file.
|
|
1891
|
+
*/
|
|
1892
|
+
get loadStats() {
|
|
1893
|
+
return this._loadStats;
|
|
1894
|
+
}
|
|
1780
1895
|
/**
|
|
1781
1896
|
* Returns file-level metadata from the QVD header.
|
|
1782
1897
|
* @return {Object} File-level metadata properties.
|
|
@@ -2126,7 +2241,8 @@ var init_QvdDataFrame = __esm({
|
|
|
2126
2241
|
* @param {string} path The path to the QVD file.
|
|
2127
2242
|
* @param {Object} [options] Optional writing options.
|
|
2128
2243
|
* @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path
|
|
2129
|
-
* must be within this directory
|
|
2244
|
+
* must be within this directory, with symlinks resolved first, so a link inside it that points
|
|
2245
|
+
* outside it is rejected. Defaults to the current working directory. To permit an entire
|
|
2130
2246
|
* volume, pass its root explicitly ('/' on POSIX, 'C:\\' on Windows); a null or empty value falls
|
|
2131
2247
|
* back to the working directory rather than removing the restriction.
|
|
2132
2248
|
* @param {Function} [options.onProgress] Optional progress callback function that receives progress updates during write operations.
|
|
@@ -2147,12 +2263,16 @@ var init_QvdDataFrame = __esm({
|
|
|
2147
2263
|
* @param {number|null} [options.maxRows] The maximum number of rows to load. Must be a non-negative
|
|
2148
2264
|
* integer; if not specified or null, all rows are loaded. Anything else throws a QvdValidationError.
|
|
2149
2265
|
* @param {string} [options.allowedDir] Optional allowed directory path. If provided, the file path
|
|
2150
|
-
* must be within this directory
|
|
2266
|
+
* must be within this directory, with symlinks resolved first, so a link inside it that points
|
|
2267
|
+
* outside it is rejected. Defaults to the current working directory. To permit an entire
|
|
2151
2268
|
* volume, pass its root explicitly ('/' on POSIX, 'C:\\' on Windows); a null or empty value falls
|
|
2152
2269
|
* back to the working directory rather than removing the restriction.
|
|
2153
|
-
* @param {number} [options.memorySafetyFactor=0.3]
|
|
2154
|
-
*
|
|
2155
|
-
*
|
|
2270
|
+
* @param {number} [options.memorySafetyFactor=0.3] Fraction (0.0-1.0) of the memory budget a load
|
|
2271
|
+
* may use. The budget is the smallest of the V8 heap limit, any container memory limit, and the
|
|
2272
|
+
* memory the OS reports as available. Default is 0.3; raise it when running with a larger heap via
|
|
2273
|
+
* --max-old-space-size. **Zero disables the memory check entirely.**
|
|
2274
|
+
* @param {number} [options.symbolFilteringThreshold=52428800] Symbol table size, in bytes, above which
|
|
2275
|
+
* a lazy load switches to the two-pass filtering path. Defaults to 50MB.
|
|
2156
2276
|
* @throws {QvdValidationError} If options.maxRows is neither null/undefined nor a non-negative integer.
|
|
2157
2277
|
* @return {Promise<QvdDataFrame>} The data frame of the QVD file.
|
|
2158
2278
|
*/
|
|
@@ -2160,7 +2280,8 @@ var init_QvdDataFrame = __esm({
|
|
|
2160
2280
|
const { QvdFileReader: QvdFileReader2 } = await Promise.resolve().then(() => (init_QvdFileReader(), QvdFileReader_exports));
|
|
2161
2281
|
const readerOptions = {
|
|
2162
2282
|
allowedDir: options.allowedDir,
|
|
2163
|
-
memorySafetyFactor: options.memorySafetyFactor
|
|
2283
|
+
memorySafetyFactor: options.memorySafetyFactor,
|
|
2284
|
+
symbolFilteringThreshold: options.symbolFilteringThreshold
|
|
2164
2285
|
};
|
|
2165
2286
|
return await new QvdFileReader2(path3, readerOptions).load(options.maxRows !== void 0 ? options.maxRows : null);
|
|
2166
2287
|
}
|