@gallop.software/studio 2.3.45 → 2.3.47

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.
@@ -208,7 +208,7 @@ async function processImage(buffer, imageKey) {
208
208
 
209
209
  // src/handlers/utils/cdn.ts
210
210
  import { promises as fs3 } from "fs";
211
- import { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3";
211
+ import { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, CopyObjectCommand } from "@aws-sdk/client-s3";
212
212
 
213
213
  // src/types.ts
214
214
  function getThumbnailPath(originalPath, size) {
@@ -400,6 +400,34 @@ async function deleteOriginalFromCdn(imageKey) {
400
400
  } catch {
401
401
  }
402
402
  }
403
+ async function copyInCdn(oldKey, newKey) {
404
+ const bucketName = process.env.CLOUDFLARE_R2_BUCKET_NAME;
405
+ if (!bucketName) throw new Error("R2 bucket not configured");
406
+ const r2 = getR2Client();
407
+ const oldKeyClean = oldKey.replace(/^\//, "");
408
+ const newKeyClean = newKey.replace(/^\//, "");
409
+ await r2.send(
410
+ new CopyObjectCommand({
411
+ Bucket: bucketName,
412
+ CopySource: `${bucketName}/${oldKeyClean}`,
413
+ Key: newKeyClean
414
+ })
415
+ );
416
+ }
417
+ async function moveInCdn(oldKey, newKey, hasThumbnails) {
418
+ await copyInCdn(oldKey, newKey);
419
+ if (hasThumbnails) {
420
+ const oldThumbPaths = getAllThumbnailPaths(oldKey);
421
+ const newThumbPaths = getAllThumbnailPaths(newKey);
422
+ for (let i = 0; i < oldThumbPaths.length; i++) {
423
+ try {
424
+ await copyInCdn(oldThumbPaths[i], newThumbPaths[i]);
425
+ } catch {
426
+ }
427
+ }
428
+ }
429
+ await deleteFromCdn(oldKey, hasThumbnails);
430
+ }
403
431
 
404
432
  // src/handlers/utils/response.ts
405
433
  function jsonResponse(data, init) {
@@ -1808,43 +1836,20 @@ async function handleMoveStream(request) {
1808
1836
  const itemCdnUrl = isItemInCloud ? cdnUrls[itemEntry.c] : void 0;
1809
1837
  const isItemInR2 = isItemInCloud && itemCdnUrl === r2PublicUrl;
1810
1838
  const itemHasThumbnails = isProcessed(itemEntry);
1839
+ let vItemMoved = false;
1811
1840
  if (isItemInR2) {
1812
1841
  try {
1813
- const itemLocalPath = getPublicPath(vItem.newKey);
1814
- const buffer = await downloadFromCdn(vItem.oldKey);
1815
- await fs6.mkdir(path6.dirname(itemLocalPath), { recursive: true });
1816
- await fs6.writeFile(itemLocalPath, buffer);
1817
- if (itemHasThumbnails) {
1818
- const oldThumbPaths = getAllThumbnailPaths(vItem.oldKey);
1819
- const newThumbPaths = getAllThumbnailPaths(vItem.newKey);
1820
- for (let t = 0; t < oldThumbPaths.length; t++) {
1821
- try {
1822
- const thumbBuffer = await downloadFromCdn(oldThumbPaths[t]);
1823
- const newThumbLocalPath = getPublicPath(newThumbPaths[t]);
1824
- await fs6.mkdir(path6.dirname(newThumbLocalPath), { recursive: true });
1825
- await fs6.writeFile(newThumbLocalPath, thumbBuffer);
1826
- } catch {
1827
- }
1828
- }
1829
- }
1830
- await deleteFromCdn(vItem.oldKey, itemHasThumbnails);
1831
- await uploadOriginalToCdn(vItem.newKey);
1832
- if (itemHasThumbnails) {
1833
- await uploadToCdn(vItem.newKey);
1834
- }
1835
- try {
1836
- await fs6.unlink(itemLocalPath);
1837
- } catch {
1838
- }
1839
- if (itemHasThumbnails) {
1840
- await deleteLocalThumbnails(vItem.newKey);
1841
- }
1842
+ await moveInCdn(vItem.oldKey, vItem.newKey, itemHasThumbnails);
1843
+ vItemMoved = true;
1842
1844
  } catch (err) {
1843
1845
  console.error(`Failed to move cloud item ${vItem.oldKey}:`, err);
1846
+ delete meta[vItem.oldKey];
1844
1847
  }
1845
1848
  }
1846
- delete meta[vItem.oldKey];
1847
- meta[vItem.newKey] = itemEntry;
1849
+ if (vItemMoved) {
1850
+ delete meta[vItem.oldKey];
1851
+ meta[vItem.newKey] = itemEntry;
1852
+ }
1848
1853
  processedFiles++;
1849
1854
  sendEvent({
1850
1855
  type: "progress",
@@ -1907,37 +1912,11 @@ async function handleMoveStream(request) {
1907
1912
  currentFile: itemName
1908
1913
  });
1909
1914
  } else if (isPushedToR2 && isImage) {
1910
- const buffer = await downloadFromCdn(oldKey);
1911
- await fs6.mkdir(path6.dirname(newAbsolutePath), { recursive: true });
1912
- await fs6.writeFile(newAbsolutePath, buffer);
1913
- let newEntry = {
1914
- o: entry?.o,
1915
- b: entry?.b
1916
- };
1917
- if (hasProcessedThumbnails) {
1918
- const processedEntry = await processImage(buffer, newKey);
1919
- newEntry = { ...newEntry, ...processedEntry };
1920
- }
1921
- await uploadOriginalToCdn(newKey);
1922
- if (hasProcessedThumbnails) {
1923
- await uploadToCdn(newKey);
1924
- }
1925
- await deleteFromCdn(oldKey, hasProcessedThumbnails);
1926
- try {
1927
- await fs6.unlink(newAbsolutePath);
1928
- } catch {
1929
- }
1930
- if (hasProcessedThumbnails) {
1931
- await deleteLocalThumbnails(newKey);
1932
- }
1933
- await deleteEmptyFolders(path6.dirname(newAbsolutePath));
1934
- if (hasProcessedThumbnails) {
1935
- const newThumbRelPath = newKey.slice(1);
1936
- await deleteEmptyFolders(path6.join(getPublicPath("images"), newThumbRelPath));
1937
- }
1938
- newEntry.c = entry?.c;
1915
+ await moveInCdn(oldKey, newKey, hasProcessedThumbnails);
1939
1916
  delete meta[oldKey];
1940
- meta[newKey] = newEntry;
1917
+ if (entry) {
1918
+ meta[newKey] = entry;
1919
+ }
1941
1920
  moved.push(itemPath);
1942
1921
  processedFiles++;
1943
1922
  sendEvent({
@@ -2095,11 +2074,7 @@ async function handleMoveStream(request) {
2095
2074
  const fileIsInR2 = fileIsInCloud && fileCdnUrl2 === r2PublicUrl;
2096
2075
  const fileHasThumbs = isProcessed(fileEntry);
2097
2076
  if (fileIsInR2) {
2098
- await deleteFromCdn(fileOldKey, fileHasThumbs);
2099
- await uploadOriginalToCdn(fileNewKey);
2100
- if (fileHasThumbs) {
2101
- await uploadToCdn(fileNewKey);
2102
- }
2077
+ await moveInCdn(fileOldKey, fileNewKey, fileHasThumbs);
2103
2078
  }
2104
2079
  delete meta[fileOldKey];
2105
2080
  meta[fileNewKey] = fileEntry;
@@ -2120,44 +2095,20 @@ async function handleMoveStream(request) {
2120
2095
  const cloudCdnUrl = cloudIsInCloud ? cdnUrls[cloudEntry.c] : void 0;
2121
2096
  const cloudIsInR2 = cloudIsInCloud && cloudCdnUrl === r2PublicUrl;
2122
2097
  const cloudHasThumbs = isProcessed(cloudEntry);
2098
+ let cloudFileMoved = false;
2123
2099
  if (cloudIsInR2) {
2124
2100
  try {
2125
- const cloudLocalPath = getPublicPath(cloudFile.newKey);
2126
- const buffer = await downloadFromCdn(cloudFile.oldKey);
2127
- await fs6.mkdir(path6.dirname(cloudLocalPath), { recursive: true });
2128
- await fs6.writeFile(cloudLocalPath, buffer);
2129
- if (cloudHasThumbs) {
2130
- const oldThumbPaths = getAllThumbnailPaths(cloudFile.oldKey);
2131
- const newThumbPaths = getAllThumbnailPaths(cloudFile.newKey);
2132
- for (let t = 0; t < oldThumbPaths.length; t++) {
2133
- try {
2134
- const thumbBuffer = await downloadFromCdn(oldThumbPaths[t]);
2135
- const newThumbLocalPath = getPublicPath(newThumbPaths[t]);
2136
- await fs6.mkdir(path6.dirname(newThumbLocalPath), { recursive: true });
2137
- await fs6.writeFile(newThumbLocalPath, thumbBuffer);
2138
- } catch {
2139
- }
2140
- }
2141
- }
2142
- await deleteFromCdn(cloudFile.oldKey, cloudHasThumbs);
2143
- await uploadOriginalToCdn(cloudFile.newKey);
2144
- if (cloudHasThumbs) {
2145
- await uploadToCdn(cloudFile.newKey);
2146
- }
2147
- try {
2148
- await fs6.unlink(cloudLocalPath);
2149
- } catch {
2150
- }
2151
- if (cloudHasThumbs) {
2152
- await deleteLocalThumbnails(cloudFile.newKey);
2153
- }
2154
- await deleteEmptyFolders(path6.dirname(cloudLocalPath));
2101
+ await moveInCdn(cloudFile.oldKey, cloudFile.newKey, cloudHasThumbs);
2102
+ cloudFileMoved = true;
2155
2103
  } catch (err) {
2156
2104
  console.error(`Failed to move cloud file ${cloudFile.oldKey}:`, err);
2105
+ delete meta[cloudFile.oldKey];
2157
2106
  }
2158
2107
  }
2159
- delete meta[cloudFile.oldKey];
2160
- meta[cloudFile.newKey] = cloudEntry;
2108
+ if (cloudFileMoved) {
2109
+ delete meta[cloudFile.oldKey];
2110
+ meta[cloudFile.newKey] = cloudEntry;
2111
+ }
2161
2112
  processedFiles++;
2162
2113
  sendEvent({
2163
2114
  type: "progress",