@gallop.software/studio 1.3.0 → 1.3.2
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/{StudioUI-K6TIH6LF.mjs → StudioUI-NXJ2QUYQ.mjs} +16 -9
- package/dist/{StudioUI-K6TIH6LF.mjs.map → StudioUI-NXJ2QUYQ.mjs.map} +1 -1
- package/dist/{StudioUI-52NHWBVJ.js → StudioUI-X22T6A7A.js} +16 -9
- package/dist/StudioUI-X22T6A7A.js.map +1 -0
- package/dist/handlers/index.js +149 -12
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/index.mjs +137 -0
- package/dist/handlers/index.mjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/StudioUI-52NHWBVJ.js.map +0 -1
package/dist/handlers/index.js
CHANGED
|
@@ -1393,9 +1393,143 @@ async function handleReprocess(request) {
|
|
|
1393
1393
|
return _server.NextResponse.json({ error: "Failed to reprocess images" }, { status: 500 });
|
|
1394
1394
|
}
|
|
1395
1395
|
}
|
|
1396
|
-
async function
|
|
1396
|
+
async function handleReprocessStream(request) {
|
|
1397
1397
|
const publicUrl = _optionalChain([process, 'access', _38 => _38.env, 'access', _39 => _39.CLOUDFLARE_R2_PUBLIC_URL, 'optionalAccess', _40 => _40.replace, 'call', _41 => _41(/\/\s*$/, "")]);
|
|
1398
1398
|
const encoder = new TextEncoder();
|
|
1399
|
+
let imageKeys;
|
|
1400
|
+
try {
|
|
1401
|
+
const body = await request.json();
|
|
1402
|
+
imageKeys = body.imageKeys;
|
|
1403
|
+
if (!imageKeys || !Array.isArray(imageKeys) || imageKeys.length === 0) {
|
|
1404
|
+
return _server.NextResponse.json({ error: "No image keys provided" }, { status: 400 });
|
|
1405
|
+
}
|
|
1406
|
+
} catch (e29) {
|
|
1407
|
+
return _server.NextResponse.json({ error: "Invalid request body" }, { status: 400 });
|
|
1408
|
+
}
|
|
1409
|
+
const stream = new ReadableStream({
|
|
1410
|
+
async start(controller) {
|
|
1411
|
+
const sendEvent = (data) => {
|
|
1412
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
1413
|
+
|
|
1414
|
+
`));
|
|
1415
|
+
};
|
|
1416
|
+
try {
|
|
1417
|
+
const meta = await loadMeta();
|
|
1418
|
+
const cdnUrls = getCdnUrls(meta);
|
|
1419
|
+
const processed = [];
|
|
1420
|
+
const errors = [];
|
|
1421
|
+
const urlsToPurge = [];
|
|
1422
|
+
const total = imageKeys.length;
|
|
1423
|
+
sendEvent({ type: "start", total });
|
|
1424
|
+
for (let i = 0; i < imageKeys.length; i++) {
|
|
1425
|
+
let imageKey = imageKeys[i];
|
|
1426
|
+
if (!imageKey.startsWith("/")) {
|
|
1427
|
+
imageKey = `/${imageKey}`;
|
|
1428
|
+
}
|
|
1429
|
+
sendEvent({
|
|
1430
|
+
type: "progress",
|
|
1431
|
+
current: i + 1,
|
|
1432
|
+
total,
|
|
1433
|
+
percent: Math.round((i + 1) / total * 100),
|
|
1434
|
+
message: `Processing ${imageKey.slice(1)}...`
|
|
1435
|
+
});
|
|
1436
|
+
try {
|
|
1437
|
+
let buffer;
|
|
1438
|
+
const entry = getMetaEntry(meta, imageKey);
|
|
1439
|
+
const existingCdnIndex = _optionalChain([entry, 'optionalAccess', _42 => _42.c]);
|
|
1440
|
+
const existingCdnUrl = existingCdnIndex !== void 0 ? cdnUrls[existingCdnIndex] : void 0;
|
|
1441
|
+
const isInOurR2 = existingCdnUrl === publicUrl;
|
|
1442
|
+
const isRemote = existingCdnIndex !== void 0 && !isInOurR2;
|
|
1443
|
+
const originalPath = _path2.default.join(process.cwd(), "public", imageKey);
|
|
1444
|
+
try {
|
|
1445
|
+
buffer = await _fs.promises.readFile(originalPath);
|
|
1446
|
+
} catch (e30) {
|
|
1447
|
+
if (isInOurR2) {
|
|
1448
|
+
buffer = await downloadFromCdn(imageKey);
|
|
1449
|
+
const dir = _path2.default.dirname(originalPath);
|
|
1450
|
+
await _fs.promises.mkdir(dir, { recursive: true });
|
|
1451
|
+
await _fs.promises.writeFile(originalPath, buffer);
|
|
1452
|
+
} else if (isRemote && existingCdnUrl) {
|
|
1453
|
+
const remoteUrl = `${existingCdnUrl}${imageKey}`;
|
|
1454
|
+
buffer = await downloadFromRemoteUrl(remoteUrl);
|
|
1455
|
+
const dir = _path2.default.dirname(originalPath);
|
|
1456
|
+
await _fs.promises.mkdir(dir, { recursive: true });
|
|
1457
|
+
await _fs.promises.writeFile(originalPath, buffer);
|
|
1458
|
+
} else {
|
|
1459
|
+
throw new Error(`File not found: ${imageKey}`);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
const ext = _path2.default.extname(imageKey).toLowerCase();
|
|
1463
|
+
const isSvg = ext === ".svg";
|
|
1464
|
+
if (isSvg) {
|
|
1465
|
+
const imageDir = _path2.default.dirname(imageKey.slice(1));
|
|
1466
|
+
const imagesPath = _path2.default.join(process.cwd(), "public", "images", imageDir === "." ? "" : imageDir);
|
|
1467
|
+
await _fs.promises.mkdir(imagesPath, { recursive: true });
|
|
1468
|
+
const fileName = _path2.default.basename(imageKey);
|
|
1469
|
+
const destPath = _path2.default.join(imagesPath, fileName);
|
|
1470
|
+
await _fs.promises.writeFile(destPath, buffer);
|
|
1471
|
+
meta[imageKey] = {
|
|
1472
|
+
...entry,
|
|
1473
|
+
o: { w: 0, h: 0 },
|
|
1474
|
+
b: "",
|
|
1475
|
+
f: { w: 0, h: 0 }
|
|
1476
|
+
};
|
|
1477
|
+
if (isRemote) {
|
|
1478
|
+
delete meta[imageKey].c;
|
|
1479
|
+
}
|
|
1480
|
+
} else {
|
|
1481
|
+
const updatedEntry = await processImage(buffer, imageKey);
|
|
1482
|
+
if (isInOurR2) {
|
|
1483
|
+
updatedEntry.c = existingCdnIndex;
|
|
1484
|
+
await uploadToCdn(imageKey);
|
|
1485
|
+
for (const thumbPath of _chunkWOHZ4LYGjs.getAllThumbnailPaths.call(void 0, imageKey)) {
|
|
1486
|
+
urlsToPurge.push(`${publicUrl}${thumbPath}`);
|
|
1487
|
+
}
|
|
1488
|
+
await deleteLocalThumbnails(imageKey);
|
|
1489
|
+
try {
|
|
1490
|
+
await _fs.promises.unlink(originalPath);
|
|
1491
|
+
} catch (e31) {
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
meta[imageKey] = updatedEntry;
|
|
1495
|
+
}
|
|
1496
|
+
processed.push(imageKey);
|
|
1497
|
+
} catch (error) {
|
|
1498
|
+
console.error(`Failed to reprocess ${imageKey}:`, error);
|
|
1499
|
+
errors.push(imageKey);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
sendEvent({ type: "cleanup", message: "Saving metadata..." });
|
|
1503
|
+
await saveMeta(meta);
|
|
1504
|
+
if (urlsToPurge.length > 0) {
|
|
1505
|
+
sendEvent({ type: "cleanup", message: "Purging CDN cache..." });
|
|
1506
|
+
await purgeCloudflareCache(urlsToPurge);
|
|
1507
|
+
}
|
|
1508
|
+
sendEvent({
|
|
1509
|
+
type: "complete",
|
|
1510
|
+
processed: processed.length,
|
|
1511
|
+
errors: errors.length,
|
|
1512
|
+
message: `Processed ${processed.length} image${processed.length !== 1 ? "s" : ""}${errors.length > 0 ? `, ${errors.length} error${errors.length !== 1 ? "s" : ""}` : ""}`
|
|
1513
|
+
});
|
|
1514
|
+
controller.close();
|
|
1515
|
+
} catch (error) {
|
|
1516
|
+
console.error("Reprocess stream error:", error);
|
|
1517
|
+
sendEvent({ type: "error", message: "Failed to process images" });
|
|
1518
|
+
controller.close();
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
});
|
|
1522
|
+
return new Response(stream, {
|
|
1523
|
+
headers: {
|
|
1524
|
+
"Content-Type": "text/event-stream",
|
|
1525
|
+
"Cache-Control": "no-cache",
|
|
1526
|
+
Connection: "keep-alive"
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
async function handleProcessAllStream() {
|
|
1531
|
+
const publicUrl = _optionalChain([process, 'access', _43 => _43.env, 'access', _44 => _44.CLOUDFLARE_R2_PUBLIC_URL, 'optionalAccess', _45 => _45.replace, 'call', _46 => _46(/\/\s*$/, "")]);
|
|
1532
|
+
const encoder = new TextEncoder();
|
|
1399
1533
|
const stream = new ReadableStream({
|
|
1400
1534
|
async start(controller) {
|
|
1401
1535
|
const sendEvent = (data) => {
|
|
@@ -1488,7 +1622,7 @@ async function handleProcessAllStream() {
|
|
|
1488
1622
|
await deleteLocalThumbnails(key);
|
|
1489
1623
|
try {
|
|
1490
1624
|
await _fs.promises.unlink(fullPath);
|
|
1491
|
-
} catch (
|
|
1625
|
+
} catch (e32) {
|
|
1492
1626
|
}
|
|
1493
1627
|
}
|
|
1494
1628
|
processed.push(key.slice(1));
|
|
@@ -1527,13 +1661,13 @@ async function handleProcessAllStream() {
|
|
|
1527
1661
|
}
|
|
1528
1662
|
}
|
|
1529
1663
|
}
|
|
1530
|
-
} catch (
|
|
1664
|
+
} catch (e33) {
|
|
1531
1665
|
}
|
|
1532
1666
|
}
|
|
1533
1667
|
const imagesDir = _path2.default.join(process.cwd(), "public", "images");
|
|
1534
1668
|
try {
|
|
1535
1669
|
await findOrphans(imagesDir);
|
|
1536
|
-
} catch (
|
|
1670
|
+
} catch (e34) {
|
|
1537
1671
|
}
|
|
1538
1672
|
async function removeEmptyDirs(dir) {
|
|
1539
1673
|
try {
|
|
@@ -1551,13 +1685,13 @@ async function handleProcessAllStream() {
|
|
|
1551
1685
|
await _fs.promises.rmdir(dir);
|
|
1552
1686
|
}
|
|
1553
1687
|
return isEmpty;
|
|
1554
|
-
} catch (
|
|
1688
|
+
} catch (e35) {
|
|
1555
1689
|
return true;
|
|
1556
1690
|
}
|
|
1557
1691
|
}
|
|
1558
1692
|
try {
|
|
1559
1693
|
await removeEmptyDirs(imagesDir);
|
|
1560
|
-
} catch (
|
|
1694
|
+
} catch (e36) {
|
|
1561
1695
|
}
|
|
1562
1696
|
await saveMeta(meta);
|
|
1563
1697
|
if (urlsToPurge.length > 0) {
|
|
@@ -1625,7 +1759,7 @@ async function handleScanStream() {
|
|
|
1625
1759
|
allFiles.push({ relativePath: relPath, fullPath });
|
|
1626
1760
|
}
|
|
1627
1761
|
}
|
|
1628
|
-
} catch (
|
|
1762
|
+
} catch (e37) {
|
|
1629
1763
|
}
|
|
1630
1764
|
}
|
|
1631
1765
|
const publicDir = _path2.default.join(process.cwd(), "public");
|
|
@@ -1684,7 +1818,7 @@ async function handleScanStream() {
|
|
|
1684
1818
|
o: { w: metadata.width || 0, h: metadata.height || 0 },
|
|
1685
1819
|
b: blurhash
|
|
1686
1820
|
};
|
|
1687
|
-
} catch (
|
|
1821
|
+
} catch (e38) {
|
|
1688
1822
|
meta[imageKey] = { o: { w: 0, h: 0 } };
|
|
1689
1823
|
}
|
|
1690
1824
|
}
|
|
@@ -1724,13 +1858,13 @@ async function handleScanStream() {
|
|
|
1724
1858
|
}
|
|
1725
1859
|
}
|
|
1726
1860
|
}
|
|
1727
|
-
} catch (
|
|
1861
|
+
} catch (e39) {
|
|
1728
1862
|
}
|
|
1729
1863
|
}
|
|
1730
1864
|
const imagesDir = _path2.default.join(process.cwd(), "public", "images");
|
|
1731
1865
|
try {
|
|
1732
1866
|
await findOrphans(imagesDir);
|
|
1733
|
-
} catch (
|
|
1867
|
+
} catch (e40) {
|
|
1734
1868
|
}
|
|
1735
1869
|
await saveMeta(meta);
|
|
1736
1870
|
sendEvent({
|
|
@@ -1797,13 +1931,13 @@ async function handleDeleteOrphans(request) {
|
|
|
1797
1931
|
await _fs.promises.rmdir(dir);
|
|
1798
1932
|
}
|
|
1799
1933
|
return isEmpty;
|
|
1800
|
-
} catch (
|
|
1934
|
+
} catch (e41) {
|
|
1801
1935
|
return true;
|
|
1802
1936
|
}
|
|
1803
1937
|
}
|
|
1804
1938
|
try {
|
|
1805
1939
|
await removeEmptyDirs(imagesDir);
|
|
1806
|
-
} catch (
|
|
1940
|
+
} catch (e42) {
|
|
1807
1941
|
}
|
|
1808
1942
|
return _server.NextResponse.json({
|
|
1809
1943
|
success: true,
|
|
@@ -1985,6 +2119,9 @@ async function POST(request) {
|
|
|
1985
2119
|
if (route === "reprocess") {
|
|
1986
2120
|
return handleReprocess(request);
|
|
1987
2121
|
}
|
|
2122
|
+
if (route === "reprocess-stream") {
|
|
2123
|
+
return handleReprocessStream(request);
|
|
2124
|
+
}
|
|
1988
2125
|
if (route === "process-all") {
|
|
1989
2126
|
return handleProcessAllStream();
|
|
1990
2127
|
}
|