@gallop.software/studio 2.3.40 → 2.3.42
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/server/index.js +173 -97
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -1725,26 +1725,134 @@ async function handleMoveStream(request) {
|
|
|
1725
1725
|
const moved = [];
|
|
1726
1726
|
const errors = [];
|
|
1727
1727
|
const sourceFolders = /* @__PURE__ */ new Set();
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
for (
|
|
1731
|
-
const itemPath = paths[i];
|
|
1728
|
+
let totalFiles = 0;
|
|
1729
|
+
const expandedItems = [];
|
|
1730
|
+
for (const itemPath of paths) {
|
|
1732
1731
|
const safePath = itemPath.replace(/\.\./g, "");
|
|
1733
1732
|
const itemName = path6.basename(safePath);
|
|
1734
|
-
const newAbsolutePath = path6.join(absoluteDestination, itemName);
|
|
1735
1733
|
const oldRelativePath = safePath.replace(/^public\/?/, "");
|
|
1736
1734
|
const destWithoutPublic = safeDestination.replace(/^public\/?/, "");
|
|
1737
1735
|
const newRelativePath = destWithoutPublic ? path6.join(destWithoutPublic, itemName) : itemName;
|
|
1738
1736
|
const oldKey = "/" + oldRelativePath;
|
|
1739
1737
|
const newKey = "/" + newRelativePath;
|
|
1738
|
+
const newAbsolutePath = path6.join(absoluteDestination, itemName);
|
|
1739
|
+
const absolutePath = getWorkspacePath(safePath);
|
|
1740
|
+
let hasLocalItem = false;
|
|
1741
|
+
let isDirectory = false;
|
|
1742
|
+
try {
|
|
1743
|
+
const stats = await fs6.stat(absolutePath);
|
|
1744
|
+
hasLocalItem = true;
|
|
1745
|
+
isDirectory = stats.isDirectory();
|
|
1746
|
+
} catch {
|
|
1747
|
+
}
|
|
1748
|
+
if (hasLocalItem && isDirectory) {
|
|
1749
|
+
const countFilesRecursive = async (dir) => {
|
|
1750
|
+
let count = 0;
|
|
1751
|
+
const entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
1752
|
+
for (const entry of entries) {
|
|
1753
|
+
if (entry.isDirectory()) {
|
|
1754
|
+
count += await countFilesRecursive(path6.join(dir, entry.name));
|
|
1755
|
+
} else {
|
|
1756
|
+
count++;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
return count;
|
|
1760
|
+
};
|
|
1761
|
+
totalFiles += await countFilesRecursive(absolutePath);
|
|
1762
|
+
expandedItems.push({ itemPath, safePath, itemName, oldKey, newKey, newAbsolutePath, isVirtualFolder: false });
|
|
1763
|
+
} else if (!hasLocalItem) {
|
|
1764
|
+
const folderPrefix = oldKey + "/";
|
|
1765
|
+
const virtualItems = [];
|
|
1766
|
+
for (const [key, metaEntry] of Object.entries(meta)) {
|
|
1767
|
+
if (key.startsWith(folderPrefix) && metaEntry && typeof metaEntry === "object") {
|
|
1768
|
+
const relativePath = key.slice(folderPrefix.length);
|
|
1769
|
+
const destNewKey = newKey + "/" + relativePath;
|
|
1770
|
+
virtualItems.push({ oldKey: key, newKey: destNewKey, entry: metaEntry });
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
if (virtualItems.length > 0) {
|
|
1774
|
+
totalFiles += virtualItems.length;
|
|
1775
|
+
expandedItems.push({ itemPath, safePath, itemName, oldKey, newKey, newAbsolutePath, isVirtualFolder: true, virtualFolderItems: virtualItems });
|
|
1776
|
+
sourceFolders.add(absolutePath);
|
|
1777
|
+
} else {
|
|
1778
|
+
totalFiles++;
|
|
1779
|
+
expandedItems.push({ itemPath, safePath, itemName, oldKey, newKey, newAbsolutePath, isVirtualFolder: false });
|
|
1780
|
+
}
|
|
1781
|
+
} else {
|
|
1782
|
+
totalFiles++;
|
|
1783
|
+
expandedItems.push({ itemPath, safePath, itemName, oldKey, newKey, newAbsolutePath, isVirtualFolder: false });
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
sendEvent({ type: "start", total: totalFiles });
|
|
1787
|
+
let processedFiles = 0;
|
|
1788
|
+
for (const expandedItem of expandedItems) {
|
|
1789
|
+
const { itemPath, safePath, itemName, oldKey, newKey, newAbsolutePath, isVirtualFolder, virtualFolderItems } = expandedItem;
|
|
1790
|
+
if (isVirtualFolder && virtualFolderItems) {
|
|
1791
|
+
for (const vItem of virtualFolderItems) {
|
|
1792
|
+
const itemEntry = vItem.entry;
|
|
1793
|
+
const isItemInCloud = itemEntry.c !== void 0;
|
|
1794
|
+
const itemCdnUrl = isItemInCloud ? cdnUrls[itemEntry.c] : void 0;
|
|
1795
|
+
const isItemInR2 = isItemInCloud && itemCdnUrl === r2PublicUrl;
|
|
1796
|
+
const itemHasThumbnails = isProcessed(itemEntry);
|
|
1797
|
+
if (isItemInR2) {
|
|
1798
|
+
try {
|
|
1799
|
+
const itemLocalPath = getPublicPath(vItem.newKey);
|
|
1800
|
+
const buffer = await downloadFromCdn(vItem.oldKey);
|
|
1801
|
+
await fs6.mkdir(path6.dirname(itemLocalPath), { recursive: true });
|
|
1802
|
+
await fs6.writeFile(itemLocalPath, buffer);
|
|
1803
|
+
if (itemHasThumbnails) {
|
|
1804
|
+
const oldThumbPaths = getAllThumbnailPaths(vItem.oldKey);
|
|
1805
|
+
const newThumbPaths = getAllThumbnailPaths(vItem.newKey);
|
|
1806
|
+
for (let t = 0; t < oldThumbPaths.length; t++) {
|
|
1807
|
+
try {
|
|
1808
|
+
const thumbBuffer = await downloadFromCdn(oldThumbPaths[t]);
|
|
1809
|
+
const newThumbLocalPath = getPublicPath(newThumbPaths[t]);
|
|
1810
|
+
await fs6.mkdir(path6.dirname(newThumbLocalPath), { recursive: true });
|
|
1811
|
+
await fs6.writeFile(newThumbLocalPath, thumbBuffer);
|
|
1812
|
+
} catch {
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
await deleteFromCdn(vItem.oldKey, itemHasThumbnails);
|
|
1817
|
+
await uploadOriginalToCdn(vItem.newKey);
|
|
1818
|
+
if (itemHasThumbnails) {
|
|
1819
|
+
await uploadToCdn(vItem.newKey);
|
|
1820
|
+
}
|
|
1821
|
+
try {
|
|
1822
|
+
await fs6.unlink(itemLocalPath);
|
|
1823
|
+
} catch {
|
|
1824
|
+
}
|
|
1825
|
+
if (itemHasThumbnails) {
|
|
1826
|
+
await deleteLocalThumbnails(vItem.newKey);
|
|
1827
|
+
}
|
|
1828
|
+
} catch (err) {
|
|
1829
|
+
console.error(`Failed to move cloud item ${vItem.oldKey}:`, err);
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
delete meta[vItem.oldKey];
|
|
1833
|
+
meta[vItem.newKey] = itemEntry;
|
|
1834
|
+
processedFiles++;
|
|
1835
|
+
sendEvent({
|
|
1836
|
+
type: "progress",
|
|
1837
|
+
current: processedFiles,
|
|
1838
|
+
total: totalFiles,
|
|
1839
|
+
moved: moved.length,
|
|
1840
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1841
|
+
currentFile: path6.basename(vItem.newKey)
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
moved.push(itemPath);
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1740
1847
|
if (meta[newKey]) {
|
|
1741
1848
|
errors.push(`${itemName} already exists in destination`);
|
|
1849
|
+
processedFiles++;
|
|
1742
1850
|
sendEvent({
|
|
1743
1851
|
type: "progress",
|
|
1744
|
-
current:
|
|
1745
|
-
total,
|
|
1852
|
+
current: processedFiles,
|
|
1853
|
+
total: totalFiles,
|
|
1746
1854
|
moved: moved.length,
|
|
1747
|
-
percent: Math.round(
|
|
1855
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1748
1856
|
currentFile: itemName
|
|
1749
1857
|
});
|
|
1750
1858
|
continue;
|
|
@@ -1771,12 +1879,13 @@ async function handleMoveStream(request) {
|
|
|
1771
1879
|
delete meta[oldKey];
|
|
1772
1880
|
meta[newKey] = newEntry;
|
|
1773
1881
|
moved.push(itemPath);
|
|
1882
|
+
processedFiles++;
|
|
1774
1883
|
sendEvent({
|
|
1775
1884
|
type: "progress",
|
|
1776
|
-
current:
|
|
1777
|
-
total,
|
|
1885
|
+
current: processedFiles,
|
|
1886
|
+
total: totalFiles,
|
|
1778
1887
|
moved: moved.length,
|
|
1779
|
-
percent: Math.round(
|
|
1888
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1780
1889
|
currentFile: itemName
|
|
1781
1890
|
});
|
|
1782
1891
|
} else if (isPushedToR2 && isImage) {
|
|
@@ -1807,106 +1916,41 @@ async function handleMoveStream(request) {
|
|
|
1807
1916
|
delete meta[oldKey];
|
|
1808
1917
|
meta[newKey] = newEntry;
|
|
1809
1918
|
moved.push(itemPath);
|
|
1919
|
+
processedFiles++;
|
|
1810
1920
|
sendEvent({
|
|
1811
1921
|
type: "progress",
|
|
1812
|
-
current:
|
|
1813
|
-
total,
|
|
1922
|
+
current: processedFiles,
|
|
1923
|
+
total: totalFiles,
|
|
1814
1924
|
moved: moved.length,
|
|
1815
|
-
percent: Math.round(
|
|
1925
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1816
1926
|
currentFile: itemName
|
|
1817
1927
|
});
|
|
1818
1928
|
} else {
|
|
1819
1929
|
const absolutePath = getWorkspacePath(safePath);
|
|
1820
1930
|
if (absoluteDestination.startsWith(absolutePath + path6.sep)) {
|
|
1821
1931
|
errors.push(`Cannot move ${itemName} into itself`);
|
|
1932
|
+
processedFiles++;
|
|
1822
1933
|
sendEvent({
|
|
1823
1934
|
type: "progress",
|
|
1824
|
-
current:
|
|
1825
|
-
total,
|
|
1935
|
+
current: processedFiles,
|
|
1936
|
+
total: totalFiles,
|
|
1826
1937
|
moved: moved.length,
|
|
1827
|
-
percent: Math.round(
|
|
1938
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1828
1939
|
currentFile: itemName
|
|
1829
1940
|
});
|
|
1830
1941
|
continue;
|
|
1831
1942
|
}
|
|
1832
|
-
let hasLocalItem = false;
|
|
1833
1943
|
try {
|
|
1834
1944
|
await fs6.access(absolutePath);
|
|
1835
|
-
hasLocalItem = true;
|
|
1836
1945
|
} catch {
|
|
1837
|
-
const folderPrefix = oldKey + "/";
|
|
1838
|
-
const hasChildrenInMeta = Object.keys(meta).some((key) => key.startsWith(folderPrefix));
|
|
1839
|
-
if (hasChildrenInMeta) {
|
|
1840
|
-
const itemsToMove = [];
|
|
1841
|
-
for (const [key, metaEntry] of Object.entries(meta)) {
|
|
1842
|
-
if (key.startsWith(folderPrefix) && metaEntry && typeof metaEntry === "object") {
|
|
1843
|
-
const relativePath = key.slice(folderPrefix.length);
|
|
1844
|
-
const destNewKey = newKey + "/" + relativePath;
|
|
1845
|
-
itemsToMove.push({ oldKey: key, newKey: destNewKey, entry: metaEntry });
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1848
|
-
for (const item of itemsToMove) {
|
|
1849
|
-
const itemEntry = item.entry;
|
|
1850
|
-
const isItemInCloud = itemEntry.c !== void 0;
|
|
1851
|
-
const itemCdnUrl = isItemInCloud ? cdnUrls[itemEntry.c] : void 0;
|
|
1852
|
-
const isItemInR2 = isItemInCloud && itemCdnUrl === r2PublicUrl;
|
|
1853
|
-
const itemHasThumbnails = isProcessed(itemEntry);
|
|
1854
|
-
if (isItemInR2) {
|
|
1855
|
-
try {
|
|
1856
|
-
const itemLocalPath = getPublicPath(item.newKey);
|
|
1857
|
-
const buffer = await downloadFromCdn(item.oldKey);
|
|
1858
|
-
await fs6.mkdir(path6.dirname(itemLocalPath), { recursive: true });
|
|
1859
|
-
await fs6.writeFile(itemLocalPath, buffer);
|
|
1860
|
-
if (itemHasThumbnails) {
|
|
1861
|
-
const oldThumbPaths = getAllThumbnailPaths(item.oldKey);
|
|
1862
|
-
const newThumbPaths = getAllThumbnailPaths(item.newKey);
|
|
1863
|
-
for (let t = 0; t < oldThumbPaths.length; t++) {
|
|
1864
|
-
try {
|
|
1865
|
-
const thumbBuffer = await downloadFromCdn(oldThumbPaths[t]);
|
|
1866
|
-
const newThumbLocalPath = getPublicPath(newThumbPaths[t]);
|
|
1867
|
-
await fs6.mkdir(path6.dirname(newThumbLocalPath), { recursive: true });
|
|
1868
|
-
await fs6.writeFile(newThumbLocalPath, thumbBuffer);
|
|
1869
|
-
} catch {
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
await deleteFromCdn(item.oldKey, itemHasThumbnails);
|
|
1874
|
-
await uploadOriginalToCdn(item.newKey);
|
|
1875
|
-
if (itemHasThumbnails) {
|
|
1876
|
-
await uploadToCdn(item.newKey);
|
|
1877
|
-
}
|
|
1878
|
-
try {
|
|
1879
|
-
await fs6.unlink(itemLocalPath);
|
|
1880
|
-
} catch {
|
|
1881
|
-
}
|
|
1882
|
-
if (itemHasThumbnails) {
|
|
1883
|
-
await deleteLocalThumbnails(item.newKey);
|
|
1884
|
-
}
|
|
1885
|
-
} catch (err) {
|
|
1886
|
-
console.error(`Failed to move cloud item ${item.oldKey}:`, err);
|
|
1887
|
-
}
|
|
1888
|
-
}
|
|
1889
|
-
delete meta[item.oldKey];
|
|
1890
|
-
meta[item.newKey] = itemEntry;
|
|
1891
|
-
}
|
|
1892
|
-
moved.push(itemPath);
|
|
1893
|
-
sendEvent({
|
|
1894
|
-
type: "progress",
|
|
1895
|
-
current: i + 1,
|
|
1896
|
-
total,
|
|
1897
|
-
moved: moved.length,
|
|
1898
|
-
percent: Math.round((i + 1) / total * 100),
|
|
1899
|
-
currentFile: itemName
|
|
1900
|
-
});
|
|
1901
|
-
continue;
|
|
1902
|
-
}
|
|
1903
1946
|
errors.push(`${itemName} not found`);
|
|
1947
|
+
processedFiles++;
|
|
1904
1948
|
sendEvent({
|
|
1905
1949
|
type: "progress",
|
|
1906
|
-
current:
|
|
1907
|
-
total,
|
|
1950
|
+
current: processedFiles,
|
|
1951
|
+
total: totalFiles,
|
|
1908
1952
|
moved: moved.length,
|
|
1909
|
-
percent: Math.round(
|
|
1953
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1910
1954
|
currentFile: itemName
|
|
1911
1955
|
});
|
|
1912
1956
|
continue;
|
|
@@ -1914,12 +1958,13 @@ async function handleMoveStream(request) {
|
|
|
1914
1958
|
try {
|
|
1915
1959
|
await fs6.access(newAbsolutePath);
|
|
1916
1960
|
errors.push(`${itemName} already exists in destination`);
|
|
1961
|
+
processedFiles++;
|
|
1917
1962
|
sendEvent({
|
|
1918
1963
|
type: "progress",
|
|
1919
|
-
current:
|
|
1920
|
-
total,
|
|
1964
|
+
current: processedFiles,
|
|
1965
|
+
total: totalFiles,
|
|
1921
1966
|
moved: moved.length,
|
|
1922
|
-
percent: Math.round(
|
|
1967
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1923
1968
|
currentFile: itemName
|
|
1924
1969
|
});
|
|
1925
1970
|
continue;
|
|
@@ -1953,26 +1998,57 @@ async function handleMoveStream(request) {
|
|
|
1953
1998
|
delete meta[key];
|
|
1954
1999
|
}
|
|
1955
2000
|
}
|
|
2001
|
+
const oldThumbRelPath = oldKey.slice(1);
|
|
2002
|
+
const newThumbRelPath = newKey.slice(1);
|
|
2003
|
+
const imagesDir = getPublicPath("images");
|
|
2004
|
+
const oldThumbFolder = path6.join(imagesDir, oldThumbRelPath);
|
|
2005
|
+
const newThumbFolder = path6.join(imagesDir, newThumbRelPath);
|
|
2006
|
+
try {
|
|
2007
|
+
await fs6.access(oldThumbFolder);
|
|
2008
|
+
sourceFolders.add(oldThumbFolder);
|
|
2009
|
+
await fs6.mkdir(path6.dirname(newThumbFolder), { recursive: true });
|
|
2010
|
+
await fs6.rename(oldThumbFolder, newThumbFolder);
|
|
2011
|
+
} catch {
|
|
2012
|
+
}
|
|
1956
2013
|
}
|
|
1957
2014
|
moved.push(itemPath);
|
|
2015
|
+
if (stats.isDirectory()) {
|
|
2016
|
+
const countFilesInDir = async (dir) => {
|
|
2017
|
+
let count = 0;
|
|
2018
|
+
const entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
2019
|
+
for (const entry2 of entries) {
|
|
2020
|
+
if (entry2.isDirectory()) {
|
|
2021
|
+
count += await countFilesInDir(path6.join(dir, entry2.name));
|
|
2022
|
+
} else {
|
|
2023
|
+
count++;
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
return count;
|
|
2027
|
+
};
|
|
2028
|
+
const filesInDir = await countFilesInDir(newAbsolutePath);
|
|
2029
|
+
processedFiles += filesInDir;
|
|
2030
|
+
} else {
|
|
2031
|
+
processedFiles++;
|
|
2032
|
+
}
|
|
1958
2033
|
sendEvent({
|
|
1959
2034
|
type: "progress",
|
|
1960
|
-
current:
|
|
1961
|
-
total,
|
|
2035
|
+
current: processedFiles,
|
|
2036
|
+
total: totalFiles,
|
|
1962
2037
|
moved: moved.length,
|
|
1963
|
-
percent: Math.round(
|
|
2038
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1964
2039
|
currentFile: itemName
|
|
1965
2040
|
});
|
|
1966
2041
|
}
|
|
1967
2042
|
} catch (err) {
|
|
1968
2043
|
console.error(`Failed to move ${itemName}:`, err);
|
|
1969
2044
|
errors.push(`Failed to move ${itemName}`);
|
|
2045
|
+
processedFiles++;
|
|
1970
2046
|
sendEvent({
|
|
1971
2047
|
type: "progress",
|
|
1972
|
-
current:
|
|
1973
|
-
total,
|
|
2048
|
+
current: processedFiles,
|
|
2049
|
+
total: totalFiles,
|
|
1974
2050
|
moved: moved.length,
|
|
1975
|
-
percent: Math.round(
|
|
2051
|
+
percent: Math.round(processedFiles / totalFiles * 100),
|
|
1976
2052
|
currentFile: itemName
|
|
1977
2053
|
});
|
|
1978
2054
|
}
|