@gallop.software/studio 0.1.102 → 0.1.103

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-STROEKU2.js.map
27
+ //# sourceMappingURL=chunk-LEOQKJCL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/chrisb/Sites/studio/dist/chunk-LEOQKJCL.js","../src/types.ts"],"names":["ext","base","outputExt"],"mappings":"AAAA;ACyEO,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;AD3E2B;AACA;AACA;AACA;AACA","file":"/Users/chrisb/Sites/studio/dist/chunk-LEOQKJCL.js","sourcesContent":[null,"/**\n * Meta entry - works for images and non-images\n * Images have w, h, b (after processing)\n * c is the index into _cdns array (omit if not on 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?: number // CDN index - index into _cdns array (omit if not on CDN)\n}\n\n/**\n * Full meta schema including special keys\n * _cdns: Array of CDN base URLs\n * Other keys: file paths from public folder\n */\nexport interface FullMeta {\n _cdns?: string[] // Array of CDN base URLs\n [key: string]: MetaEntry | string[] | undefined\n}\n\n/**\n * Meta schema - keyed by path from public folder (legacy type)\n * Example: { \"/portfolio/photo.jpg\": { w: 2400, h: 1600, b: \"...\" } }\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 cdnBaseUrl?: string // CDN base URL when pushed to cloud\n isRemote?: boolean // true if CDN URL doesn't match R2 (external import)\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"]}
@@ -24,4 +24,4 @@ export {
24
24
  getThumbnailPath,
25
25
  getAllThumbnailPaths
26
26
  };
27
- //# sourceMappingURL=chunk-CIJTQ7TB.mjs.map
27
+ //# sourceMappingURL=chunk-RDNC5ABF.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["/**\n * Meta entry - works for images and non-images\n * Images have w, h, b (after processing)\n * c is the index into _cdns array (omit if not on 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?: number // CDN index - index into _cdns array (omit if not on CDN)\n}\n\n/**\n * Full meta schema including special keys\n * _cdns: Array of CDN base URLs\n * Other keys: file paths from public folder\n */\nexport interface FullMeta {\n _cdns?: string[] // Array of CDN base URLs\n [key: string]: MetaEntry | string[] | undefined\n}\n\n/**\n * Meta schema - keyed by path from public folder (legacy type)\n * Example: { \"/portfolio/photo.jpg\": { w: 2400, h: 1600, b: \"...\" } }\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 cdnBaseUrl?: string // CDN base URL when pushed to cloud\n isRemote?: boolean // true if CDN URL doesn't match R2 (external import)\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"],"mappings":";AAyEO,SAAS,iBAAiB,cAAsB,MAA2C;AAChG,MAAI,SAAS,QAAQ;AACnB,UAAMA,OAAM,aAAa,MAAM,QAAQ,IAAI,CAAC,KAAK;AACjD,UAAMC,QAAO,aAAa,QAAQ,UAAU,EAAE;AAC9C,UAAMC,aAAYF,KAAI,YAAY,MAAM,SAAS,SAAS;AAC1D,WAAO,UAAUC,KAAI,GAAGC,UAAS;AAAA,EACnC;AACA,QAAM,MAAM,aAAa,MAAM,QAAQ,IAAI,CAAC,KAAK;AACjD,QAAM,OAAO,aAAa,QAAQ,UAAU,EAAE;AAC9C,QAAM,YAAY,IAAI,YAAY,MAAM,SAAS,SAAS;AAC1D,SAAO,UAAU,IAAI,IAAI,IAAI,GAAG,SAAS;AAC3C;AAKO,SAAS,qBAAqB,cAAgC;AACnE,SAAO;AAAA,IACL,iBAAiB,cAAc,MAAM;AAAA,IACrC,iBAAiB,cAAc,IAAI;AAAA,IACnC,iBAAiB,cAAc,IAAI;AAAA,IACnC,iBAAiB,cAAc,IAAI;AAAA,EACrC;AACF;","names":["ext","base","outputExt"]}
@@ -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 _chunkSTROEKU2js = require('../chunk-STROEKU2.js');
4
+ var _chunkLEOQKJCLjs = require('../chunk-LEOQKJCL.js');
5
5
 
6
6
  // src/handlers/index.ts
7
7
  var _server = require('next/server');
@@ -185,7 +185,7 @@ async function uploadToCdn(imageKey) {
185
185
  const bucketName = process.env.CLOUDFLARE_R2_BUCKET_NAME;
186
186
  if (!bucketName) throw new Error("R2 bucket not configured");
187
187
  const r2 = getR2Client();
188
- for (const thumbPath of _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, imageKey)) {
188
+ for (const thumbPath of _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, imageKey)) {
189
189
  const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
190
190
  try {
191
191
  const fileBuffer = await _fs.promises.readFile(localPath);
@@ -202,7 +202,7 @@ async function uploadToCdn(imageKey) {
202
202
  }
203
203
  }
204
204
  async function deleteLocalThumbnails(imageKey) {
205
- for (const thumbPath of _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, imageKey)) {
205
+ for (const thumbPath of _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, imageKey)) {
206
206
  const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
207
207
  try {
208
208
  await _fs.promises.unlink(localPath);
@@ -219,6 +219,7 @@ async function handleList(request) {
219
219
  const meta = await loadMeta();
220
220
  const fileEntries = getFileEntries(meta);
221
221
  const cdnUrls = getCdnUrls(meta);
222
+ const r2PublicUrl = _optionalChain([process, 'access', _ => _.env, 'access', _2 => _2.CLOUDFLARE_R2_PUBLIC_URL, 'optionalAccess', _3 => _3.replace, 'call', _4 => _4(/\/$/, "")]) || "";
222
223
  if (fileEntries.length === 0) {
223
224
  return _server.NextResponse.json({ items: [], isEmpty: true });
224
225
  }
@@ -253,11 +254,13 @@ async function handleList(request) {
253
254
  const fileName = remaining;
254
255
  const isImage = isImageFile(fileName);
255
256
  const isPushedToCloud = entry.c !== void 0;
257
+ const fileCdnUrl = isPushedToCloud && entry.c !== void 0 ? cdnUrls[entry.c] : void 0;
258
+ const isRemote = isPushedToCloud && (!r2PublicUrl || fileCdnUrl !== r2PublicUrl);
256
259
  let thumbnail;
257
260
  let hasThumbnail = false;
258
261
  let fileSize;
259
262
  if (isImage && entry.p === 1) {
260
- const thumbPath = _chunkSTROEKU2js.getThumbnailPath.call(void 0, key, "sm");
263
+ const thumbPath = _chunkLEOQKJCLjs.getThumbnailPath.call(void 0, key, "sm");
261
264
  if (isPushedToCloud && entry.c !== void 0) {
262
265
  const cdnUrl = cdnUrls[entry.c];
263
266
  if (cdnUrl) {
@@ -301,7 +304,8 @@ async function handleList(request) {
301
304
  hasThumbnail,
302
305
  isProcessed: entry.p === 1,
303
306
  cdnPushed: isPushedToCloud,
304
- cdnBaseUrl: isPushedToCloud && entry.c !== void 0 ? cdnUrls[entry.c] : void 0,
307
+ cdnBaseUrl: fileCdnUrl,
308
+ isRemote,
305
309
  dimensions: entry.w && entry.h ? { width: entry.w, height: entry.h } : void 0
306
310
  });
307
311
  }
@@ -314,7 +318,7 @@ async function handleList(request) {
314
318
  }
315
319
  async function handleSearch(request) {
316
320
  const searchParams = request.nextUrl.searchParams;
317
- const query = _optionalChain([searchParams, 'access', _ => _.get, 'call', _2 => _2("q"), 'optionalAccess', _3 => _3.toLowerCase, 'call', _4 => _4()]) || "";
321
+ const query = _optionalChain([searchParams, 'access', _5 => _5.get, 'call', _6 => _6("q"), 'optionalAccess', _7 => _7.toLowerCase, 'call', _8 => _8()]) || "";
318
322
  if (query.length < 2) {
319
323
  return _server.NextResponse.json({ items: [] });
320
324
  }
@@ -322,6 +326,7 @@ async function handleSearch(request) {
322
326
  const meta = await loadMeta();
323
327
  const fileEntries = getFileEntries(meta);
324
328
  const cdnUrls = getCdnUrls(meta);
329
+ const r2PublicUrl = _optionalChain([process, 'access', _9 => _9.env, 'access', _10 => _10.CLOUDFLARE_R2_PUBLIC_URL, 'optionalAccess', _11 => _11.replace, 'call', _12 => _12(/\/$/, "")]) || "";
325
330
  const items = [];
326
331
  for (const [key, entry] of fileEntries) {
327
332
  if (!key.toLowerCase().includes(query)) continue;
@@ -329,10 +334,12 @@ async function handleSearch(request) {
329
334
  const relativePath = key.slice(1);
330
335
  const isImage = isImageFile(fileName);
331
336
  const isPushedToCloud = entry.c !== void 0;
337
+ const fileCdnUrl = isPushedToCloud && entry.c !== void 0 ? cdnUrls[entry.c] : void 0;
338
+ const isRemote = isPushedToCloud && (!r2PublicUrl || fileCdnUrl !== r2PublicUrl);
332
339
  let thumbnail;
333
340
  let hasThumbnail = false;
334
341
  if (isImage && entry.p === 1) {
335
- const thumbPath = _chunkSTROEKU2js.getThumbnailPath.call(void 0, key, "sm");
342
+ const thumbPath = _chunkLEOQKJCLjs.getThumbnailPath.call(void 0, key, "sm");
336
343
  if (isPushedToCloud && entry.c !== void 0) {
337
344
  const cdnUrl = cdnUrls[entry.c];
338
345
  if (cdnUrl) {
@@ -367,7 +374,8 @@ async function handleSearch(request) {
367
374
  hasThumbnail,
368
375
  isProcessed: entry.p === 1,
369
376
  cdnPushed: isPushedToCloud,
370
- cdnBaseUrl: isPushedToCloud && entry.c !== void 0 ? cdnUrls[entry.c] : void 0,
377
+ cdnBaseUrl: fileCdnUrl,
378
+ isRemote,
371
379
  dimensions: entry.w && entry.h ? { width: entry.w, height: entry.h } : void 0
372
380
  });
373
381
  }
@@ -562,7 +570,7 @@ async function handleDelete(request) {
562
570
  const absolutePath = _path2.default.join(process.cwd(), itemPath);
563
571
  const imageKey = "/" + itemPath.replace(/^public\//, "");
564
572
  const entry = meta[imageKey];
565
- const isPushedToCloud = _optionalChain([entry, 'optionalAccess', _5 => _5.c]) === 1;
573
+ const isPushedToCloud = _optionalChain([entry, 'optionalAccess', _13 => _13.c]) === 1;
566
574
  try {
567
575
  const stats = await _fs.promises.stat(absolutePath);
568
576
  if (stats.isDirectory()) {
@@ -571,7 +579,7 @@ async function handleDelete(request) {
571
579
  for (const key of Object.keys(meta)) {
572
580
  if (key.startsWith(prefix) || key === imageKey) {
573
581
  if (!meta[key].c) {
574
- for (const thumbPath of _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, key)) {
582
+ for (const thumbPath of _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, key)) {
575
583
  const absoluteThumbPath = _path2.default.join(process.cwd(), "public", thumbPath);
576
584
  try {
577
585
  await _fs.promises.unlink(absoluteThumbPath);
@@ -587,7 +595,7 @@ async function handleDelete(request) {
587
595
  const isInImagesFolder = itemPath.startsWith("public/images/");
588
596
  if (!isInImagesFolder && entry) {
589
597
  if (!isPushedToCloud) {
590
- for (const thumbPath of _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, imageKey)) {
598
+ for (const thumbPath of _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, imageKey)) {
591
599
  const absoluteThumbPath = _path2.default.join(process.cwd(), "public", thumbPath);
592
600
  try {
593
601
  await _fs.promises.unlink(absoluteThumbPath);
@@ -699,8 +707,8 @@ async function handleRename(request) {
699
707
  const newKey = "/" + newRelativePath;
700
708
  if (meta[oldKey]) {
701
709
  const entry = meta[oldKey];
702
- const oldThumbPaths = _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, oldKey);
703
- const newThumbPaths = _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, newKey);
710
+ const oldThumbPaths = _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, oldKey);
711
+ const newThumbPaths = _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, newKey);
704
712
  for (let i = 0; i < oldThumbPaths.length; i++) {
705
713
  const oldThumbPath = _path2.default.join(process.cwd(), "public", oldThumbPaths[i]);
706
714
  const newThumbPath = _path2.default.join(process.cwd(), "public", newThumbPaths[i]);
@@ -779,8 +787,8 @@ async function handleMove(request) {
779
787
  const newKey = "/" + newRelativePath;
780
788
  if (meta[oldKey]) {
781
789
  const entry = meta[oldKey];
782
- const oldThumbPaths = _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, oldKey);
783
- const newThumbPaths = _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, newKey);
790
+ const oldThumbPaths = _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, oldKey);
791
+ const newThumbPaths = _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, newKey);
784
792
  for (let i = 0; i < oldThumbPaths.length; i++) {
785
793
  const oldThumbPath = _path2.default.join(process.cwd(), "public", oldThumbPaths[i]);
786
794
  const newThumbPath = _path2.default.join(process.cwd(), "public", newThumbPaths[i]);
@@ -875,7 +883,7 @@ async function handleSync(request) {
875
883
  errors.push(`Original file not found: ${imageKey}`);
876
884
  continue;
877
885
  }
878
- for (const thumbPath of _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, imageKey)) {
886
+ for (const thumbPath of _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, imageKey)) {
879
887
  const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
880
888
  try {
881
889
  const fileBuffer = await _fs.promises.readFile(localPath);
@@ -891,7 +899,7 @@ async function handleSync(request) {
891
899
  }
892
900
  }
893
901
  entry.c = cdnIndex;
894
- for (const thumbPath of _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, imageKey)) {
902
+ for (const thumbPath of _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, imageKey)) {
895
903
  const localPath = _path2.default.join(process.cwd(), "public", thumbPath);
896
904
  try {
897
905
  await _fs.promises.unlink(localPath);
@@ -932,8 +940,8 @@ async function handleReprocess(request) {
932
940
  try {
933
941
  let buffer;
934
942
  const entry = getMetaEntry(meta, imageKey);
935
- const isPushedToCloud = _optionalChain([entry, 'optionalAccess', _6 => _6.c]) !== void 0;
936
- const existingCdnIndex = _optionalChain([entry, 'optionalAccess', _7 => _7.c]);
943
+ const isPushedToCloud = _optionalChain([entry, 'optionalAccess', _14 => _14.c]) !== void 0;
944
+ const existingCdnIndex = _optionalChain([entry, 'optionalAccess', _15 => _15.c]);
937
945
  const originalPath = _path2.default.join(process.cwd(), "public", imageKey);
938
946
  try {
939
947
  buffer = await _fs.promises.readFile(originalPath);
@@ -1067,7 +1075,7 @@ async function handleProcessAllStream() {
1067
1075
  const trackedPaths = /* @__PURE__ */ new Set();
1068
1076
  for (const [imageKey, entry] of getFileEntries(meta)) {
1069
1077
  if (entry.c === void 0) {
1070
- for (const thumbPath of _chunkSTROEKU2js.getAllThumbnailPaths.call(void 0, imageKey)) {
1078
+ for (const thumbPath of _chunkLEOQKJCLjs.getAllThumbnailPaths.call(void 0, imageKey)) {
1071
1079
  trackedPaths.add(thumbPath);
1072
1080
  }
1073
1081
  }