@lvce-editor/file-system-process 5.15.1 → 5.16.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.js +176 -52
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -666,7 +666,7 @@ const isWebSocketOpen = async webSocket => {
|
|
|
666
666
|
};
|
|
667
667
|
|
|
668
668
|
// @ts-ignore
|
|
669
|
-
const serialize = message => {
|
|
669
|
+
const serialize$1 = message => {
|
|
670
670
|
return JSON.stringify(message);
|
|
671
671
|
};
|
|
672
672
|
|
|
@@ -734,7 +734,7 @@ const wrap$9 = webSocket => {
|
|
|
734
734
|
},
|
|
735
735
|
// @ts-ignore
|
|
736
736
|
send(message) {
|
|
737
|
-
const stringifiedMessage = serialize(message);
|
|
737
|
+
const stringifiedMessage = serialize$1(message);
|
|
738
738
|
wrap.webSocket.send(stringifiedMessage);
|
|
739
739
|
},
|
|
740
740
|
start() {
|
|
@@ -778,10 +778,10 @@ const execute = (command, ...args) => {
|
|
|
778
778
|
|
|
779
779
|
const Two$1 = '2.0';
|
|
780
780
|
const callbacks = Object.create(null);
|
|
781
|
-
const get$
|
|
781
|
+
const get$2 = id => {
|
|
782
782
|
return callbacks[id];
|
|
783
783
|
};
|
|
784
|
-
const remove$
|
|
784
|
+
const remove$3 = id => {
|
|
785
785
|
delete callbacks[id];
|
|
786
786
|
};
|
|
787
787
|
class JsonRpcError extends Error {
|
|
@@ -968,14 +968,14 @@ const warn = (...args) => {
|
|
|
968
968
|
console.warn(...args);
|
|
969
969
|
};
|
|
970
970
|
const resolve = (id, response) => {
|
|
971
|
-
const fn = get$
|
|
971
|
+
const fn = get$2(id);
|
|
972
972
|
if (!fn) {
|
|
973
973
|
console.log(response);
|
|
974
974
|
warn(`callback ${id} may already be disposed`);
|
|
975
975
|
return;
|
|
976
976
|
}
|
|
977
977
|
fn(response);
|
|
978
|
-
remove$
|
|
978
|
+
remove$3(id);
|
|
979
979
|
};
|
|
980
980
|
const E_COMMAND_NOT_FOUND = 'E_COMMAND_NOT_FOUND';
|
|
981
981
|
const getErrorType = prettyError => {
|
|
@@ -1402,13 +1402,13 @@ const createMockRpc = ({
|
|
|
1402
1402
|
};
|
|
1403
1403
|
|
|
1404
1404
|
const rpcs = Object.create(null);
|
|
1405
|
-
const set$
|
|
1405
|
+
const set$3 = (id, rpc) => {
|
|
1406
1406
|
rpcs[id] = rpc;
|
|
1407
1407
|
};
|
|
1408
|
-
const get = id => {
|
|
1408
|
+
const get$1 = id => {
|
|
1409
1409
|
return rpcs[id];
|
|
1410
1410
|
};
|
|
1411
|
-
const remove$
|
|
1411
|
+
const remove$2 = id => {
|
|
1412
1412
|
delete rpcs[id];
|
|
1413
1413
|
};
|
|
1414
1414
|
|
|
@@ -1416,18 +1416,18 @@ const remove$1 = id => {
|
|
|
1416
1416
|
const create$1 = rpcId => {
|
|
1417
1417
|
return {
|
|
1418
1418
|
async dispose() {
|
|
1419
|
-
const rpc = get(rpcId);
|
|
1419
|
+
const rpc = get$1(rpcId);
|
|
1420
1420
|
await rpc.dispose();
|
|
1421
1421
|
},
|
|
1422
1422
|
// @ts-ignore
|
|
1423
1423
|
invoke(method, ...params) {
|
|
1424
|
-
const rpc = get(rpcId);
|
|
1424
|
+
const rpc = get$1(rpcId);
|
|
1425
1425
|
// @ts-ignore
|
|
1426
1426
|
return rpc.invoke(method, ...params);
|
|
1427
1427
|
},
|
|
1428
1428
|
// @ts-ignore
|
|
1429
1429
|
invokeAndTransfer(method, ...params) {
|
|
1430
|
-
const rpc = get(rpcId);
|
|
1430
|
+
const rpc = get$1(rpcId);
|
|
1431
1431
|
// @ts-ignore
|
|
1432
1432
|
return rpc.invokeAndTransfer(method, ...params);
|
|
1433
1433
|
},
|
|
@@ -1435,16 +1435,16 @@ const create$1 = rpcId => {
|
|
|
1435
1435
|
const mockRpc = createMockRpc({
|
|
1436
1436
|
commandMap
|
|
1437
1437
|
});
|
|
1438
|
-
set$
|
|
1438
|
+
set$3(rpcId, mockRpc);
|
|
1439
1439
|
// @ts-ignore
|
|
1440
1440
|
mockRpc[Symbol.dispose] = () => {
|
|
1441
|
-
remove$
|
|
1441
|
+
remove$2(rpcId);
|
|
1442
1442
|
};
|
|
1443
1443
|
// @ts-ignore
|
|
1444
1444
|
return mockRpc;
|
|
1445
1445
|
},
|
|
1446
1446
|
set(rpc) {
|
|
1447
|
-
set$
|
|
1447
|
+
set$3(rpcId, rpc);
|
|
1448
1448
|
}
|
|
1449
1449
|
};
|
|
1450
1450
|
};
|
|
@@ -1455,20 +1455,20 @@ const SharedProcess = 1492;
|
|
|
1455
1455
|
|
|
1456
1456
|
const {
|
|
1457
1457
|
invoke: invoke$1,
|
|
1458
|
-
set: set$
|
|
1458
|
+
set: set$2
|
|
1459
1459
|
} = create$1(MainProcess);
|
|
1460
1460
|
|
|
1461
1461
|
const {
|
|
1462
1462
|
invoke,
|
|
1463
1463
|
invokeAndTransfer,
|
|
1464
|
-
set
|
|
1464
|
+
set: set$1
|
|
1465
1465
|
} = create$1(SharedProcess);
|
|
1466
1466
|
|
|
1467
|
-
const state = {
|
|
1467
|
+
const state$1 = {
|
|
1468
1468
|
id: 0
|
|
1469
1469
|
};
|
|
1470
1470
|
const create = () => {
|
|
1471
|
-
return ++state.id;
|
|
1471
|
+
return ++state$1.id;
|
|
1472
1472
|
};
|
|
1473
1473
|
|
|
1474
1474
|
const ports = Object.create(null);
|
|
@@ -1513,7 +1513,7 @@ const initializeMainProcessRpc = async () => {
|
|
|
1513
1513
|
await invokeAndTransfer('TemporaryMessagePort.sendToElectron', port, MainProcess, FileSystemProcess);
|
|
1514
1514
|
}
|
|
1515
1515
|
});
|
|
1516
|
-
set$
|
|
1516
|
+
set$2(rpc);
|
|
1517
1517
|
};
|
|
1518
1518
|
|
|
1519
1519
|
const assertUri = uri => {
|
|
@@ -1529,6 +1529,149 @@ const ENOENT = 'ENOENT';
|
|
|
1529
1529
|
const EROFS = 'EROFS';
|
|
1530
1530
|
const EXDEV = 'EXDEV';
|
|
1531
1531
|
|
|
1532
|
+
const cacheVersion = 1;
|
|
1533
|
+
const maxEntries = 50_000;
|
|
1534
|
+
const cacheFolderName = 'file-system-process';
|
|
1535
|
+
const cacheFileName = 'file-hashes-v1.json';
|
|
1536
|
+
const state = {
|
|
1537
|
+
cacheFilePath: '',
|
|
1538
|
+
cacheFolderPath: '',
|
|
1539
|
+
entries: new Map(),
|
|
1540
|
+
loadPromise: undefined,
|
|
1541
|
+
persistedRevision: 0,
|
|
1542
|
+
revision: 0,
|
|
1543
|
+
writePromise: undefined
|
|
1544
|
+
};
|
|
1545
|
+
const isSerializedCache = value => {
|
|
1546
|
+
if (!value || typeof value !== 'object') {
|
|
1547
|
+
return false;
|
|
1548
|
+
}
|
|
1549
|
+
const candidate = value;
|
|
1550
|
+
return candidate.version === cacheVersion && Array.isArray(candidate.entries);
|
|
1551
|
+
};
|
|
1552
|
+
const isSerializedEntry = value => {
|
|
1553
|
+
return Array.isArray(value) && value.length === 3 && typeof value[0] === 'string' && typeof value[1] === 'string' && typeof value[2] === 'string' && /^[\da-f]{64}$/.test(value[2]);
|
|
1554
|
+
};
|
|
1555
|
+
const parseCache = content => {
|
|
1556
|
+
const parsed = JSON.parse(content);
|
|
1557
|
+
if (!isSerializedCache(parsed) || !parsed.entries.every(isSerializedEntry)) {
|
|
1558
|
+
return undefined;
|
|
1559
|
+
}
|
|
1560
|
+
return parsed.entries.slice(-maxEntries);
|
|
1561
|
+
};
|
|
1562
|
+
const load = async () => {
|
|
1563
|
+
if (!state.cacheFilePath) {
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
try {
|
|
1567
|
+
const content = await fs.readFile(state.cacheFilePath, 'utf8');
|
|
1568
|
+
const cachedEntries = parseCache(content);
|
|
1569
|
+
if (!cachedEntries) {
|
|
1570
|
+
return;
|
|
1571
|
+
}
|
|
1572
|
+
for (const [path, fingerprint, hash] of cachedEntries) {
|
|
1573
|
+
state.entries.delete(path);
|
|
1574
|
+
state.entries.set(path, {
|
|
1575
|
+
fingerprint,
|
|
1576
|
+
hash
|
|
1577
|
+
});
|
|
1578
|
+
}
|
|
1579
|
+
} catch {
|
|
1580
|
+
// A persistent cache miss must fall back to hashing the source files.
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
const configure = cacheDirectory => {
|
|
1584
|
+
state.entries.clear();
|
|
1585
|
+
state.cacheFolderPath = cacheDirectory ? join(cacheDirectory, cacheFolderName) : '';
|
|
1586
|
+
state.cacheFilePath = state.cacheFolderPath ? join(state.cacheFolderPath, cacheFileName) : '';
|
|
1587
|
+
state.loadPromise = undefined;
|
|
1588
|
+
state.persistedRevision = 0;
|
|
1589
|
+
state.revision = 0;
|
|
1590
|
+
state.writePromise = undefined;
|
|
1591
|
+
};
|
|
1592
|
+
const ensureLoaded = async () => {
|
|
1593
|
+
state.loadPromise ||= load();
|
|
1594
|
+
await state.loadPromise;
|
|
1595
|
+
};
|
|
1596
|
+
const get = (path, fingerprint) => {
|
|
1597
|
+
const entry = state.entries.get(path);
|
|
1598
|
+
if (!entry || entry.fingerprint !== fingerprint) {
|
|
1599
|
+
return undefined;
|
|
1600
|
+
}
|
|
1601
|
+
state.entries.delete(path);
|
|
1602
|
+
state.entries.set(path, entry);
|
|
1603
|
+
return entry.hash;
|
|
1604
|
+
};
|
|
1605
|
+
const set = (path, fingerprint, hash) => {
|
|
1606
|
+
const previous = state.entries.get(path);
|
|
1607
|
+
state.entries.delete(path);
|
|
1608
|
+
state.entries.set(path, {
|
|
1609
|
+
fingerprint,
|
|
1610
|
+
hash
|
|
1611
|
+
});
|
|
1612
|
+
if (!previous || previous.fingerprint !== fingerprint || previous.hash !== hash) {
|
|
1613
|
+
state.revision++;
|
|
1614
|
+
}
|
|
1615
|
+
if (state.entries.size <= maxEntries) {
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
const oldestPath = state.entries.keys().next().value;
|
|
1619
|
+
if (oldestPath !== undefined) {
|
|
1620
|
+
state.entries.delete(oldestPath);
|
|
1621
|
+
state.revision++;
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
const remove$1 = path => {
|
|
1625
|
+
if (state.entries.delete(path)) {
|
|
1626
|
+
state.revision++;
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
const serialize = () => {
|
|
1630
|
+
const serializedEntries = Array.from(state.entries, ([path, entry]) => [path, entry.fingerprint, entry.hash]);
|
|
1631
|
+
return JSON.stringify({
|
|
1632
|
+
entries: serializedEntries,
|
|
1633
|
+
version: cacheVersion
|
|
1634
|
+
});
|
|
1635
|
+
};
|
|
1636
|
+
const writeCurrentState = async () => {
|
|
1637
|
+
while (state.cacheFilePath && state.persistedRevision !== state.revision) {
|
|
1638
|
+
const snapshotRevision = state.revision;
|
|
1639
|
+
const temporaryPath = `${state.cacheFilePath}.${process.pid}.tmp`;
|
|
1640
|
+
try {
|
|
1641
|
+
await fs.mkdir(state.cacheFolderPath, {
|
|
1642
|
+
recursive: true
|
|
1643
|
+
});
|
|
1644
|
+
await fs.writeFile(temporaryPath, serialize());
|
|
1645
|
+
await fs.rename(temporaryPath, state.cacheFilePath);
|
|
1646
|
+
state.persistedRevision = snapshotRevision;
|
|
1647
|
+
} catch {
|
|
1648
|
+
try {
|
|
1649
|
+
await fs.rm(temporaryPath, {
|
|
1650
|
+
force: true
|
|
1651
|
+
});
|
|
1652
|
+
} catch {
|
|
1653
|
+
// Best-effort cleanup only.
|
|
1654
|
+
}
|
|
1655
|
+
return;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
};
|
|
1659
|
+
const flush = async () => {
|
|
1660
|
+
await ensureLoaded();
|
|
1661
|
+
if (!state.cacheFilePath) {
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1664
|
+
const writePromise = state.writePromise || writeCurrentState();
|
|
1665
|
+
state.writePromise = writePromise;
|
|
1666
|
+
try {
|
|
1667
|
+
await writePromise;
|
|
1668
|
+
} finally {
|
|
1669
|
+
if (state.writePromise === writePromise) {
|
|
1670
|
+
state.writePromise = undefined;
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
};
|
|
1674
|
+
|
|
1532
1675
|
const getDisplayPath = path => {
|
|
1533
1676
|
if (path === '') {
|
|
1534
1677
|
return '<empty string>';
|
|
@@ -1682,44 +1825,21 @@ const readFile = async (uri, encoding = Utf8) => {
|
|
|
1682
1825
|
throw new VError(error, `Failed to read file "${uri}"`);
|
|
1683
1826
|
}
|
|
1684
1827
|
};
|
|
1685
|
-
const fileHashCache = new Map();
|
|
1686
|
-
const maxFileHashCacheEntries = 50_000;
|
|
1687
1828
|
const getFileFingerprint = stats => {
|
|
1688
1829
|
return `${stats.dev}:${stats.ino}:${stats.size}:${stats.mtimeNs}:${stats.ctimeNs}`;
|
|
1689
1830
|
};
|
|
1690
|
-
const getCachedFileHash = (path, fingerprint) => {
|
|
1691
|
-
const entry = fileHashCache.get(path);
|
|
1692
|
-
if (!entry || entry.fingerprint !== fingerprint) {
|
|
1693
|
-
return undefined;
|
|
1694
|
-
}
|
|
1695
|
-
fileHashCache.delete(path);
|
|
1696
|
-
fileHashCache.set(path, entry);
|
|
1697
|
-
return entry.hash;
|
|
1698
|
-
};
|
|
1699
|
-
const setCachedFileHash = (path, fingerprint, hash) => {
|
|
1700
|
-
fileHashCache.delete(path);
|
|
1701
|
-
fileHashCache.set(path, {
|
|
1702
|
-
fingerprint,
|
|
1703
|
-
hash
|
|
1704
|
-
});
|
|
1705
|
-
if (fileHashCache.size <= maxFileHashCacheEntries) {
|
|
1706
|
-
return;
|
|
1707
|
-
}
|
|
1708
|
-
const oldestPath = fileHashCache.keys().next().value;
|
|
1709
|
-
if (oldestPath) {
|
|
1710
|
-
fileHashCache.delete(oldestPath);
|
|
1711
|
-
}
|
|
1712
|
-
};
|
|
1713
1831
|
const getFileHash = async uri => {
|
|
1832
|
+
let path = '';
|
|
1714
1833
|
try {
|
|
1715
1834
|
string(uri);
|
|
1716
1835
|
assertUri(uri);
|
|
1717
|
-
|
|
1836
|
+
path = fileURLToPath(uri);
|
|
1837
|
+
await ensureLoaded();
|
|
1718
1838
|
const statsBeforeRead = await fs.stat(path, {
|
|
1719
1839
|
bigint: true
|
|
1720
1840
|
});
|
|
1721
1841
|
const fingerprintBeforeRead = getFileFingerprint(statsBeforeRead);
|
|
1722
|
-
const cachedHash =
|
|
1842
|
+
const cachedHash = get(path, fingerprintBeforeRead);
|
|
1723
1843
|
if (cachedHash) {
|
|
1724
1844
|
return cachedHash;
|
|
1725
1845
|
}
|
|
@@ -1730,11 +1850,14 @@ const getFileHash = async uri => {
|
|
|
1730
1850
|
});
|
|
1731
1851
|
const fingerprintAfterRead = getFileFingerprint(statsAfterRead);
|
|
1732
1852
|
if (fingerprintBeforeRead === fingerprintAfterRead) {
|
|
1733
|
-
|
|
1853
|
+
set(path, fingerprintAfterRead, hash);
|
|
1734
1854
|
}
|
|
1735
1855
|
return hash;
|
|
1736
1856
|
} catch (error) {
|
|
1737
1857
|
if (isEnoentError(error)) {
|
|
1858
|
+
if (path) {
|
|
1859
|
+
remove$1(path);
|
|
1860
|
+
}
|
|
1738
1861
|
throw new FileNotFoundError(uri);
|
|
1739
1862
|
}
|
|
1740
1863
|
throw new VError(error, `Failed to hash file "${uri}"`);
|
|
@@ -1768,6 +1891,7 @@ const getFileHashes = async uris => {
|
|
|
1768
1891
|
await Promise.all(Array.from({
|
|
1769
1892
|
length: workerCount
|
|
1770
1893
|
}, hashNext));
|
|
1894
|
+
await flush();
|
|
1771
1895
|
return hashes;
|
|
1772
1896
|
};
|
|
1773
1897
|
const writeFile = async (uri, content, encoding = Utf8) => {
|
|
@@ -2009,7 +2133,7 @@ const handleElectronMessagePort = async (messagePort, rpcId) => {
|
|
|
2009
2133
|
requiresSocket: false
|
|
2010
2134
|
});
|
|
2011
2135
|
if (rpcId) {
|
|
2012
|
-
set$
|
|
2136
|
+
set$3(rpcId, rpc);
|
|
2013
2137
|
}
|
|
2014
2138
|
};
|
|
2015
2139
|
|
|
@@ -2027,8 +2151,8 @@ const handleWebSocket = async (handle, request) => {
|
|
|
2027
2151
|
});
|
|
2028
2152
|
};
|
|
2029
2153
|
|
|
2030
|
-
const initialize = async
|
|
2031
|
-
|
|
2154
|
+
const initialize = async cacheDirectory => {
|
|
2155
|
+
configure(cacheDirectory);
|
|
2032
2156
|
};
|
|
2033
2157
|
|
|
2034
2158
|
const commandMap = {
|
|
@@ -2080,7 +2204,7 @@ const getRpc = argv => {
|
|
|
2080
2204
|
const initializeParentProcessRpc = async argv => {
|
|
2081
2205
|
const rpc = await getRpc(argv);
|
|
2082
2206
|
// TODO we don't know at this point if we have been launched by shared process or electron main process
|
|
2083
|
-
set(rpc);
|
|
2207
|
+
set$1(rpc);
|
|
2084
2208
|
};
|
|
2085
2209
|
|
|
2086
2210
|
const listen = async argv => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/file-system-process",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.16.0",
|
|
4
4
|
"description": "File System Process",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Lvce Editor",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"trash": "^10.1.1",
|
|
22
|
-
"ws": "^8.21.
|
|
22
|
+
"ws": "^8.21.3"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|
|
25
25
|
"node": ">=24"
|