@gallop.software/studio 1.2.0 → 1.2.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.
@@ -311,6 +311,22 @@ async function deleteFromCdn(imageKey, hasThumbnails) {
311
311
  }
312
312
 
313
313
  // src/handlers/list.ts
314
+ function getExistingThumbnails(originalPath, entry) {
315
+ const thumbnails = [];
316
+ if (entry.f) {
317
+ thumbnails.push({ path: getThumbnailPath(originalPath, "full"), size: "f" });
318
+ }
319
+ if (entry.lg) {
320
+ thumbnails.push({ path: getThumbnailPath(originalPath, "lg"), size: "lg" });
321
+ }
322
+ if (entry.md) {
323
+ thumbnails.push({ path: getThumbnailPath(originalPath, "md"), size: "md" });
324
+ }
325
+ if (entry.sm) {
326
+ thumbnails.push({ path: getThumbnailPath(originalPath, "sm"), size: "sm" });
327
+ }
328
+ return thumbnails;
329
+ }
314
330
  async function handleList(request) {
315
331
  const searchParams = request.nextUrl.searchParams;
316
332
  const requestedPath = searchParams.get("path") || "public";
@@ -325,6 +341,84 @@ async function handleList(request) {
325
341
  const seenFolders = /* @__PURE__ */ new Set();
326
342
  const metaKeys = fileEntries.map(([key]) => key);
327
343
  const isInsideImagesFolder = relativePath === "images" || relativePath.startsWith("images/");
344
+ if (isInsideImagesFolder) {
345
+ const imagesSubPath = relativePath.replace(/^images\/?/, "");
346
+ const imagesPrefix = imagesSubPath ? `/${imagesSubPath}/` : "/";
347
+ const allThumbnails = [];
348
+ for (const [key, entry] of fileEntries) {
349
+ if (isProcessed(entry)) {
350
+ const thumbnails = getExistingThumbnails(key, entry);
351
+ for (const thumb of thumbnails) {
352
+ allThumbnails.push({ ...thumb, originalKey: key });
353
+ }
354
+ }
355
+ }
356
+ for (const thumb of allThumbnails) {
357
+ const thumbRelative = thumb.path.replace(/^\/images\/?/, "");
358
+ if (imagesSubPath === "") {
359
+ const slashIndex = thumbRelative.indexOf("/");
360
+ if (slashIndex === -1) {
361
+ const fileName = thumbRelative;
362
+ items.push({
363
+ name: fileName,
364
+ path: `public/images/${fileName}`,
365
+ type: "file",
366
+ thumbnail: thumb.path,
367
+ hasThumbnail: false,
368
+ isProtected: true
369
+ });
370
+ } else {
371
+ const folderName = thumbRelative.slice(0, slashIndex);
372
+ if (!seenFolders.has(folderName)) {
373
+ seenFolders.add(folderName);
374
+ const folderPrefix = `/${folderName}/`;
375
+ const fileCount = allThumbnails.filter(
376
+ (t) => t.path.replace(/^\/images/, "").startsWith(folderPrefix)
377
+ ).length;
378
+ items.push({
379
+ name: folderName,
380
+ path: `public/images/${folderName}`,
381
+ type: "folder",
382
+ fileCount,
383
+ isProtected: true
384
+ });
385
+ }
386
+ }
387
+ } else {
388
+ if (!thumbRelative.startsWith(imagesSubPath + "/") && thumbRelative !== imagesSubPath) continue;
389
+ const remaining = thumbRelative.slice(imagesSubPath.length + 1);
390
+ if (!remaining) continue;
391
+ const slashIndex = remaining.indexOf("/");
392
+ if (slashIndex === -1) {
393
+ items.push({
394
+ name: remaining,
395
+ path: `public/images/${imagesSubPath}/${remaining}`,
396
+ type: "file",
397
+ thumbnail: thumb.path,
398
+ hasThumbnail: false,
399
+ isProtected: true
400
+ });
401
+ } else {
402
+ const folderName = remaining.slice(0, slashIndex);
403
+ if (!seenFolders.has(folderName)) {
404
+ seenFolders.add(folderName);
405
+ const folderPrefix = `${imagesSubPath}/${folderName}/`;
406
+ const fileCount = allThumbnails.filter(
407
+ (t) => t.path.replace(/^\/images\//, "").startsWith(folderPrefix)
408
+ ).length;
409
+ items.push({
410
+ name: folderName,
411
+ path: `public/images/${imagesSubPath}/${folderName}`,
412
+ type: "folder",
413
+ fileCount,
414
+ isProtected: true
415
+ });
416
+ }
417
+ }
418
+ }
419
+ }
420
+ return NextResponse.json({ items });
421
+ }
328
422
  const absoluteDir = path5.join(process.cwd(), requestedPath);
329
423
  try {
330
424
  const dirEntries = await fs4.readdir(absoluteDir, { withFileTypes: true });
@@ -336,12 +430,11 @@ async function handleList(request) {
336
430
  const isImagesFolder = entry.name === "images" && !relativePath;
337
431
  const folderPath = relativePath ? `public/${relativePath}/${entry.name}` : `public/${entry.name}`;
338
432
  let fileCount = 0;
339
- if (isInsideImagesFolder || isImagesFolder) {
340
- const subDir = path5.join(absoluteDir, entry.name);
341
- try {
342
- const subEntries = await fs4.readdir(subDir);
343
- fileCount = subEntries.filter((f) => !f.startsWith(".")).length;
344
- } catch {
433
+ if (isImagesFolder) {
434
+ for (const [key, metaEntry] of fileEntries) {
435
+ if (isProcessed(metaEntry)) {
436
+ fileCount += getExistingThumbnails(key, metaEntry).length;
437
+ }
345
438
  }
346
439
  } else {
347
440
  const folderPrefix = pathPrefix === "/" ? `/${entry.name}/` : `${pathPrefix}${entry.name}/`;
@@ -354,32 +447,30 @@ async function handleList(request) {
354
447
  path: folderPath,
355
448
  type: "folder",
356
449
  fileCount,
357
- isProtected: isImagesFolder || isInsideImagesFolder
450
+ isProtected: isImagesFolder
358
451
  });
359
452
  }
360
- } else if (isInsideImagesFolder) {
361
- const filePath = relativePath ? `public/${relativePath}/${entry.name}` : `public/${entry.name}`;
362
- const fullPath = path5.join(absoluteDir, entry.name);
363
- let fileSize;
364
- try {
365
- const stats = await fs4.stat(fullPath);
366
- fileSize = stats.size;
367
- } catch {
368
- }
369
- const isImage = isImageFile(entry.name);
370
- items.push({
371
- name: entry.name,
372
- path: filePath,
373
- type: "file",
374
- size: fileSize,
375
- thumbnail: isImage ? `/${relativePath}/${entry.name}` : void 0,
376
- hasThumbnail: false,
377
- isProtected: true
378
- });
379
453
  }
380
454
  }
381
455
  } catch {
382
456
  }
457
+ if (!relativePath && !seenFolders.has("images")) {
458
+ let thumbnailCount = 0;
459
+ for (const [key, entry] of fileEntries) {
460
+ if (isProcessed(entry)) {
461
+ thumbnailCount += getExistingThumbnails(key, entry).length;
462
+ }
463
+ }
464
+ if (thumbnailCount > 0) {
465
+ items.push({
466
+ name: "images",
467
+ path: "public/images",
468
+ type: "folder",
469
+ fileCount: thumbnailCount,
470
+ isProtected: true
471
+ });
472
+ }
473
+ }
383
474
  if (fileEntries.length === 0 && items.length === 0) {
384
475
  return NextResponse.json({ items: [], isEmpty: true });
385
476
  }
@@ -705,11 +796,10 @@ async function handleUpload(request) {
705
796
  try {
706
797
  const metadata = await sharp2(buffer).metadata();
707
798
  meta[imageKey] = {
708
- w: metadata.width || 0,
709
- h: metadata.height || 0
799
+ o: { w: metadata.width || 0, h: metadata.height || 0 }
710
800
  };
711
801
  } catch {
712
- meta[imageKey] = { w: 0, h: 0 };
802
+ meta[imageKey] = { o: { w: 0, h: 0 } };
713
803
  }
714
804
  } else {
715
805
  meta[imageKey] = {};
@@ -744,7 +834,7 @@ async function handleDelete(request) {
744
834
  const absolutePath = path6.join(process.cwd(), itemPath);
745
835
  const imageKey = "/" + itemPath.replace(/^public\//, "");
746
836
  const entry = meta[imageKey];
747
- const isPushedToCloud = entry?.c === 1;
837
+ const isPushedToCloud = entry?.c !== void 0;
748
838
  try {
749
839
  const stats = await fs5.stat(absolutePath);
750
840
  if (stats.isDirectory()) {
@@ -752,7 +842,8 @@ async function handleDelete(request) {
752
842
  const prefix = imageKey + "/";
753
843
  for (const key of Object.keys(meta)) {
754
844
  if (key.startsWith(prefix) || key === imageKey) {
755
- if (!meta[key].c) {
845
+ const keyEntry = meta[key];
846
+ if (keyEntry && keyEntry.c === void 0) {
756
847
  for (const thumbPath of getAllThumbnailPaths(key)) {
757
848
  const absoluteThumbPath = path6.join(process.cwd(), "public", thumbPath);
758
849
  try {