@gallop.software/studio 0.1.91 → 0.1.92

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.
@@ -24,4 +24,4 @@ function getAllThumbnailPaths(originalPath) {
24
24
 
25
25
 
26
26
  exports.getThumbnailPath = getThumbnailPath; exports.getAllThumbnailPaths = getAllThumbnailPaths;
27
- //# sourceMappingURL=chunk-RURSHIQJ.js.map
27
+ //# sourceMappingURL=chunk-L36EH3PM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/chrisb/Sites/studio/dist/chunk-L36EH3PM.js","../src/types.ts"],"names":["ext","base","outputExt"],"mappings":"AAAA;AC6DO,SAAS,gBAAA,CAAiB,YAAA,EAAsB,IAAA,EAA2C;AAChG,EAAA,GAAA,CAAI,KAAA,IAAS,MAAA,EAAQ;AACnB,IAAA,MAAMA,KAAAA,kBAAM,YAAA,mBAAa,KAAA,mBAAM,QAAQ,CAAA,4BAAA,CAAI,CAAC,IAAA,GAAK,MAAA;AACjD,IAAA,MAAMC,MAAAA,EAAO,YAAA,CAAa,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA;AAC9C,IAAA,MAAMC,WAAAA,EAAYF,IAAAA,CAAI,WAAA,CAAY,EAAA,IAAM,OAAA,EAAS,OAAA,EAAS,MAAA;AAC1D,IAAA,OAAO,CAAA,OAAA,EAAUC,KAAI,CAAA,EAAA;AACvB,EAAA;AACyB,EAAA;AACZ,EAAA;AACS,EAAA;AACG,EAAA;AAC3B;AAKgB;AACP,EAAA;AACY,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACnB,EAAA;AACF;AD/D2B;AACA;AACA;AACA;AACA","file":"/Users/chrisb/Sites/studio/dist/chunk-L36EH3PM.js","sourcesContent":[null,"/**\n * Meta entry - works for images and non-images\n * Images have w, h, b (after processing)\n * Non-images just have c (if pushed to CDN)\n */\nexport interface MetaEntry {\n w?: number // original width (images only)\n h?: number // original height (images only)\n b?: string // blurhash (images only, after processing)\n p?: 1 // processed (has thumbnails and blurhash)\n c?: 1 // pushed to CDN (omit if not pushed)\n}\n\n/**\n * Meta schema - keyed by path from public folder\n * Example: { \"/portfolio/photo.jpg\": { w: 2400, h: 1600, blur: \"...\" } }\n */\nexport type LeanMeta = Record<string, MetaEntry>\n\n// Legacy alias for compatibility\nexport type LeanImageEntry = MetaEntry\n\n/**\n * File/folder item for browser\n */\nexport interface FileItem {\n name: string\n path: string\n type: 'file' | 'folder'\n size?: number\n dimensions?: { width: number; height: number }\n isProcessed?: boolean\n cdnPushed?: boolean\n // Folder-specific properties\n fileCount?: number\n totalSize?: number\n // For showing thumbnails - path to -sm version if exists\n thumbnail?: string\n // Whether a processed thumbnail exists\n hasThumbnail?: boolean\n}\n\n/**\n * Studio configuration\n */\nexport interface StudioConfig {\n r2AccountId?: string\n r2AccessKeyId?: string\n r2SecretAccessKey?: string\n r2BucketName?: string\n r2PublicUrl?: string\n thumbnailSizes?: {\n small: number\n medium: number\n large: number\n }\n}\n\n/**\n * Get thumbnail path from original image path\n */\nexport function getThumbnailPath(originalPath: string, size: 'sm' | 'md' | 'lg' | 'full'): string {\n if (size === 'full') {\n const ext = originalPath.match(/\\.\\w+$/)?.[0] || '.jpg'\n const base = originalPath.replace(/\\.\\w+$/, '')\n const outputExt = ext.toLowerCase() === '.png' ? '.png' : '.jpg'\n return `/images${base}${outputExt}`\n }\n const ext = originalPath.match(/\\.\\w+$/)?.[0] || '.jpg'\n const base = originalPath.replace(/\\.\\w+$/, '')\n const outputExt = ext.toLowerCase() === '.png' ? '.png' : '.jpg'\n return `/images${base}-${size}${outputExt}`\n}\n\n/**\n * Get all thumbnail paths for an image\n */\nexport function getAllThumbnailPaths(originalPath: string): string[] {\n return [\n getThumbnailPath(originalPath, 'full'),\n getThumbnailPath(originalPath, 'lg'),\n getThumbnailPath(originalPath, 'md'),\n getThumbnailPath(originalPath, 'sm'),\n ]\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { F as FileItem } from '../types-DuX-sfUL.mjs';
1
+ import { F as FileItem } from '../types-C4hCz2w8.mjs';
2
2
  import { NextRequest, NextResponse } from 'next/server';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { F as FileItem } from '../types-DuX-sfUL.js';
1
+ import { F as FileItem } from '../types-C4hCz2w8.js';
2
2
  import { NextRequest, NextResponse } from 'next/server';
3
3
 
4
4
  /**
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
- var _chunkRURSHIQJjs = require('../chunk-RURSHIQJ.js');
4
+ var _chunkL36EH3PMjs = require('../chunk-L36EH3PM.js');
5
5
 
6
6
  // src/handlers/index.ts
7
7
  var _server = require('next/server');
@@ -156,7 +156,7 @@ async function uploadToCdn(imageKey) {
156
156
  const bucketName = process.env.CLOUDFLARE_R2_BUCKET_NAME;
157
157
  if (!bucketName) throw new Error("R2 bucket not configured");
158
158
  const r2 = getR2Client();
159
- for (const thumbPath of _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, imageKey)) {
159
+ for (const thumbPath of _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, imageKey)) {
160
160
  const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
161
161
  try {
162
162
  const fileBuffer = await _fs.promises.readFile(localPath);
@@ -173,7 +173,7 @@ async function uploadToCdn(imageKey) {
173
173
  }
174
174
  }
175
175
  async function deleteLocalThumbnails(imageKey) {
176
- for (const thumbPath of _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, imageKey)) {
176
+ for (const thumbPath of _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, imageKey)) {
177
177
  const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
178
178
  try {
179
179
  await _fs.promises.unlink(localPath);
@@ -227,7 +227,7 @@ async function handleList(request) {
227
227
  let hasThumbnail = false;
228
228
  let fileSize;
229
229
  if (isImage && (entry.w || entry.b)) {
230
- const thumbPath = _chunkRURSHIQJjs.getThumbnailPath.call(void 0, key, "sm");
230
+ const thumbPath = _chunkL36EH3PMjs.getThumbnailPath.call(void 0, key, "sm");
231
231
  if (isPushedToCloud) {
232
232
  const cdnUrl = process.env.CLOUDFLARE_R2_PUBLIC_URL || process.env.NEXT_PUBLIC_CLOUDFLARE_R2_PUBLIC_URL;
233
233
  if (cdnUrl) {
@@ -264,6 +264,7 @@ async function handleList(request) {
264
264
  size: fileSize,
265
265
  thumbnail,
266
266
  hasThumbnail,
267
+ isProcessed: entry.p === 1,
267
268
  cdnPushed: isPushedToCloud,
268
269
  dimensions: entry.w && entry.h ? { width: entry.w, height: entry.h } : void 0
269
270
  });
@@ -293,7 +294,7 @@ async function handleSearch(request) {
293
294
  let thumbnail;
294
295
  let hasThumbnail = false;
295
296
  if (isImage && (entry.w || entry.b)) {
296
- const thumbPath = _chunkRURSHIQJjs.getThumbnailPath.call(void 0, key, "sm");
297
+ const thumbPath = _chunkL36EH3PMjs.getThumbnailPath.call(void 0, key, "sm");
297
298
  if (isPushedToCloud) {
298
299
  const cdnUrl = process.env.CLOUDFLARE_R2_PUBLIC_URL || process.env.NEXT_PUBLIC_CLOUDFLARE_R2_PUBLIC_URL;
299
300
  if (cdnUrl) {
@@ -321,6 +322,7 @@ async function handleSearch(request) {
321
322
  type: "file",
322
323
  thumbnail,
323
324
  hasThumbnail,
325
+ isProcessed: entry.p === 1,
324
326
  cdnPushed: isPushedToCloud,
325
327
  dimensions: entry.w && entry.h ? { width: entry.w, height: entry.h } : void 0
326
328
  });
@@ -522,7 +524,7 @@ async function handleDelete(request) {
522
524
  for (const key of Object.keys(meta)) {
523
525
  if (key.startsWith(prefix) || key === imageKey) {
524
526
  if (!meta[key].c) {
525
- for (const thumbPath of _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, key)) {
527
+ for (const thumbPath of _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, key)) {
526
528
  const absoluteThumbPath = _path2.default.join(process.cwd(), "public", thumbPath);
527
529
  try {
528
530
  await _fs.promises.unlink(absoluteThumbPath);
@@ -538,7 +540,7 @@ async function handleDelete(request) {
538
540
  const isInImagesFolder = itemPath.startsWith("public/images/");
539
541
  if (!isInImagesFolder && entry) {
540
542
  if (!isPushedToCloud) {
541
- for (const thumbPath of _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, imageKey)) {
543
+ for (const thumbPath of _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, imageKey)) {
542
544
  const absoluteThumbPath = _path2.default.join(process.cwd(), "public", thumbPath);
543
545
  try {
544
546
  await _fs.promises.unlink(absoluteThumbPath);
@@ -650,8 +652,8 @@ async function handleRename(request) {
650
652
  const newKey = "/" + newRelativePath;
651
653
  if (meta[oldKey]) {
652
654
  const entry = meta[oldKey];
653
- const oldThumbPaths = _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, oldKey);
654
- const newThumbPaths = _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, newKey);
655
+ const oldThumbPaths = _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, oldKey);
656
+ const newThumbPaths = _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, newKey);
655
657
  for (let i = 0; i < oldThumbPaths.length; i++) {
656
658
  const oldThumbPath = _path2.default.join(process.cwd(), "public", oldThumbPaths[i]);
657
659
  const newThumbPath = _path2.default.join(process.cwd(), "public", newThumbPaths[i]);
@@ -730,8 +732,8 @@ async function handleMove(request) {
730
732
  const newKey = "/" + newRelativePath;
731
733
  if (meta[oldKey]) {
732
734
  const entry = meta[oldKey];
733
- const oldThumbPaths = _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, oldKey);
734
- const newThumbPaths = _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, newKey);
735
+ const oldThumbPaths = _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, oldKey);
736
+ const newThumbPaths = _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, newKey);
735
737
  for (let i = 0; i < oldThumbPaths.length; i++) {
736
738
  const oldThumbPath = _path2.default.join(process.cwd(), "public", oldThumbPaths[i]);
737
739
  const newThumbPath = _path2.default.join(process.cwd(), "public", newThumbPaths[i]);
@@ -805,6 +807,10 @@ async function handleSync(request) {
805
807
  pushed.push(imageKey);
806
808
  continue;
807
809
  }
810
+ if (!entry.p) {
811
+ errors.push(`Image not processed: ${imageKey}. Run Process Images first.`);
812
+ continue;
813
+ }
808
814
  try {
809
815
  const originalLocalPath = _path2.default.join(process.cwd(), "public", imageKey);
810
816
  try {
@@ -821,7 +827,7 @@ async function handleSync(request) {
821
827
  errors.push(`Original file not found: ${imageKey}`);
822
828
  continue;
823
829
  }
824
- for (const thumbPath of _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, imageKey)) {
830
+ for (const thumbPath of _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, imageKey)) {
825
831
  const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
826
832
  try {
827
833
  const fileBuffer = await _fs.promises.readFile(localPath);
@@ -837,7 +843,7 @@ async function handleSync(request) {
837
843
  }
838
844
  }
839
845
  entry.c = 1;
840
- for (const thumbPath of _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, imageKey)) {
846
+ for (const thumbPath of _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, imageKey)) {
841
847
  const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
842
848
  try {
843
849
  await _fs.promises.unlink(localPath);
@@ -935,16 +941,11 @@ async function handleProcessAllStream() {
935
941
  const errors = [];
936
942
  const orphansRemoved = [];
937
943
  let alreadyProcessed = 0;
938
- let pushedToCloud = 0;
939
944
  const imagesToProcess = [];
940
945
  for (const [key, entry] of Object.entries(meta)) {
941
946
  const fileName = _path2.default.basename(key);
942
947
  if (!isImageFile(fileName)) continue;
943
- if (entry.c) {
944
- pushedToCloud++;
945
- continue;
946
- }
947
- if (!entry.b) {
948
+ if (!entry.p) {
948
949
  imagesToProcess.push({ key, entry });
949
950
  } else {
950
951
  alreadyProcessed++;
@@ -953,8 +954,9 @@ async function handleProcessAllStream() {
953
954
  const total = imagesToProcess.length;
954
955
  sendEvent({ type: "start", total });
955
956
  for (let i = 0; i < imagesToProcess.length; i++) {
956
- const { key } = imagesToProcess[i];
957
+ const { key, entry } = imagesToProcess[i];
957
958
  const fullPath = _path2.default.join(process.cwd(), "public", key);
959
+ const isInCloud = entry.c === 1;
958
960
  sendEvent({
959
961
  type: "progress",
960
962
  current: i + 1,
@@ -964,7 +966,15 @@ async function handleProcessAllStream() {
964
966
  // Remove leading /
965
967
  });
966
968
  try {
967
- const buffer = await _fs.promises.readFile(fullPath);
969
+ let buffer;
970
+ if (isInCloud) {
971
+ buffer = await downloadFromCdn(key);
972
+ const dir = _path2.default.dirname(fullPath);
973
+ await _fs.promises.mkdir(dir, { recursive: true });
974
+ await _fs.promises.writeFile(fullPath, buffer);
975
+ } else {
976
+ buffer = await _fs.promises.readFile(fullPath);
977
+ }
968
978
  const ext = _path2.default.extname(key).toLowerCase();
969
979
  const isSvg = ext === ".svg";
970
980
  if (isSvg) {
@@ -975,13 +985,27 @@ async function handleProcessAllStream() {
975
985
  const destPath = _path2.default.join(imagesPath, fileName);
976
986
  await _fs.promises.writeFile(destPath, buffer);
977
987
  meta[key] = {
988
+ ...entry,
978
989
  w: 0,
979
990
  h: 0,
980
- b: ""
991
+ b: "",
992
+ p: 1
981
993
  };
982
994
  } else {
983
995
  const processedEntry = await processImage(buffer, key);
984
- meta[key] = processedEntry;
996
+ meta[key] = {
997
+ ...processedEntry,
998
+ p: 1,
999
+ ...isInCloud ? { c: 1 } : {}
1000
+ };
1001
+ }
1002
+ if (isInCloud) {
1003
+ await uploadToCdn(key);
1004
+ await deleteLocalThumbnails(key);
1005
+ try {
1006
+ await _fs.promises.unlink(fullPath);
1007
+ } catch (e25) {
1008
+ }
985
1009
  }
986
1010
  processed.push(key.slice(1));
987
1011
  } catch (error) {
@@ -993,7 +1017,7 @@ async function handleProcessAllStream() {
993
1017
  const trackedPaths = /* @__PURE__ */ new Set();
994
1018
  for (const imageKey of Object.keys(meta)) {
995
1019
  if (!meta[imageKey].c) {
996
- for (const thumbPath of _chunkRURSHIQJjs.getAllThumbnailPaths.call(void 0, imageKey)) {
1020
+ for (const thumbPath of _chunkL36EH3PMjs.getAllThumbnailPaths.call(void 0, imageKey)) {
997
1021
  trackedPaths.add(thumbPath);
998
1022
  }
999
1023
  }
@@ -1019,13 +1043,13 @@ async function handleProcessAllStream() {
1019
1043
  }
1020
1044
  }
1021
1045
  }
1022
- } catch (e25) {
1046
+ } catch (e26) {
1023
1047
  }
1024
1048
  }
1025
1049
  const imagesDir = _path2.default.join(process.cwd(), "public", "images");
1026
1050
  try {
1027
1051
  await findOrphans(imagesDir);
1028
- } catch (e26) {
1052
+ } catch (e27) {
1029
1053
  }
1030
1054
  async function removeEmptyDirs(dir) {
1031
1055
  try {
@@ -1043,20 +1067,19 @@ async function handleProcessAllStream() {
1043
1067
  await _fs.promises.rmdir(dir);
1044
1068
  }
1045
1069
  return isEmpty;
1046
- } catch (e27) {
1070
+ } catch (e28) {
1047
1071
  return true;
1048
1072
  }
1049
1073
  }
1050
1074
  try {
1051
1075
  await removeEmptyDirs(imagesDir);
1052
- } catch (e28) {
1076
+ } catch (e29) {
1053
1077
  }
1054
1078
  await saveMeta(meta);
1055
1079
  sendEvent({
1056
1080
  type: "complete",
1057
1081
  processed: processed.length,
1058
1082
  alreadyProcessed,
1059
- pushedToCloud,
1060
1083
  orphansRemoved: orphansRemoved.length,
1061
1084
  errors: errors.length
1062
1085
  });
@@ -1111,7 +1134,7 @@ async function handleScanStream() {
1111
1134
  allFiles.push({ relativePath: relPath, fullPath });
1112
1135
  }
1113
1136
  }
1114
- } catch (e29) {
1137
+ } catch (e30) {
1115
1138
  }
1116
1139
  }
1117
1140
  const publicDir = _path2.default.join(process.cwd(), "public");
@@ -1167,7 +1190,7 @@ async function handleScanStream() {
1167
1190
  w: metadata.width || 0,
1168
1191
  h: metadata.height || 0
1169
1192
  };
1170
- } catch (e30) {
1193
+ } catch (e31) {
1171
1194
  meta[imageKey] = { w: 0, h: 0 };
1172
1195
  }
1173
1196
  }