@gallop.software/studio 2.3.64 → 2.3.66

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.
@@ -11,7 +11,7 @@
11
11
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
12
12
  }
13
13
  </style>
14
- <script type="module" crossorigin src="/assets/index-pIYJJxxv.js"></script>
14
+ <script type="module" crossorigin src="/assets/index-B-L7Nl0F.js"></script>
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -2278,6 +2278,197 @@ async function handleDelete(request) {
2278
2278
  return jsonResponse({ error: "Failed to delete files" }, { status: 500 });
2279
2279
  }
2280
2280
  }
2281
+ async function handleDeleteStream(request) {
2282
+ const encoder = new TextEncoder();
2283
+ const stream = new ReadableStream({
2284
+ async start(controller) {
2285
+ const sendEvent = (data) => {
2286
+ try {
2287
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
2288
+
2289
+ `));
2290
+ } catch {
2291
+ }
2292
+ };
2293
+ try {
2294
+ const { paths, operationId } = await request.json();
2295
+ if (!paths || !Array.isArray(paths) || paths.length === 0) {
2296
+ sendEvent({ type: "error", message: "No paths provided" });
2297
+ controller.close();
2298
+ return;
2299
+ }
2300
+ const isCancelled = () => operationId ? isOperationCancelled(operationId) : false;
2301
+ const meta = await loadMeta();
2302
+ const deleted = [];
2303
+ const errors = [];
2304
+ const sourceFolders = /* @__PURE__ */ new Set();
2305
+ const total = paths.length;
2306
+ sendEvent({ type: "start", total });
2307
+ for (let i = 0; i < paths.length; i++) {
2308
+ if (isCancelled()) {
2309
+ await saveMeta(meta);
2310
+ for (const folder of sourceFolders) {
2311
+ await deleteEmptyFolders(folder);
2312
+ }
2313
+ if (operationId) clearCancelledOperation(operationId);
2314
+ sendEvent({
2315
+ type: "complete",
2316
+ deleted: deleted.length,
2317
+ errors: errors.length,
2318
+ message: `Stopped. Deleted ${deleted.length} item${deleted.length !== 1 ? "s" : ""}.`,
2319
+ cancelled: true
2320
+ });
2321
+ controller.close();
2322
+ return;
2323
+ }
2324
+ const itemPath = paths[i];
2325
+ try {
2326
+ if (!itemPath.startsWith("public/")) {
2327
+ errors.push(`Invalid path: ${itemPath}`);
2328
+ sendEvent({
2329
+ type: "progress",
2330
+ current: i + 1,
2331
+ total,
2332
+ deleted: deleted.length,
2333
+ percent: Math.round((i + 1) / total * 100),
2334
+ currentFile: path7.basename(itemPath)
2335
+ });
2336
+ continue;
2337
+ }
2338
+ const absolutePath = getWorkspacePath(itemPath);
2339
+ const imageKey = "/" + itemPath.replace(/^public\//, "");
2340
+ sourceFolders.add(path7.dirname(absolutePath));
2341
+ const entry = meta[imageKey];
2342
+ const isPushedToCloud = entry?.c !== void 0;
2343
+ const hasThumbnails = entry ? isProcessed(entry) : false;
2344
+ try {
2345
+ const stats = await fs7.stat(absolutePath);
2346
+ if (stats.isDirectory()) {
2347
+ await fs7.rm(absolutePath, { recursive: true });
2348
+ const prefix = imageKey + "/";
2349
+ for (const key of Object.keys(meta)) {
2350
+ if (key.startsWith(prefix) || key === imageKey) {
2351
+ const keyEntry = meta[key];
2352
+ const keyHasThumbnails = keyEntry ? isProcessed(keyEntry) : false;
2353
+ if (keyEntry?.c !== void 0) {
2354
+ try {
2355
+ await deleteFromCdn(key, keyHasThumbnails);
2356
+ } catch {
2357
+ }
2358
+ } else {
2359
+ for (const thumbPath of getAllThumbnailPaths(key)) {
2360
+ const absoluteThumbPath = getPublicPath(thumbPath);
2361
+ try {
2362
+ await fs7.unlink(absoluteThumbPath);
2363
+ } catch {
2364
+ }
2365
+ }
2366
+ }
2367
+ delete meta[key];
2368
+ }
2369
+ }
2370
+ } else {
2371
+ await fs7.unlink(absolutePath);
2372
+ const isInImagesFolder = itemPath.startsWith("public/images/");
2373
+ if (!isInImagesFolder && entry) {
2374
+ if (isPushedToCloud) {
2375
+ try {
2376
+ await deleteFromCdn(imageKey, hasThumbnails);
2377
+ } catch {
2378
+ }
2379
+ } else {
2380
+ for (const thumbPath of getAllThumbnailPaths(imageKey)) {
2381
+ const absoluteThumbPath = getPublicPath(thumbPath);
2382
+ try {
2383
+ await fs7.unlink(absoluteThumbPath);
2384
+ } catch {
2385
+ }
2386
+ }
2387
+ }
2388
+ delete meta[imageKey];
2389
+ }
2390
+ }
2391
+ } catch {
2392
+ if (entry) {
2393
+ if (isPushedToCloud) {
2394
+ try {
2395
+ await deleteFromCdn(imageKey, hasThumbnails);
2396
+ } catch {
2397
+ }
2398
+ }
2399
+ delete meta[imageKey];
2400
+ } else {
2401
+ const prefix = imageKey + "/";
2402
+ let foundAny = false;
2403
+ for (const key of Object.keys(meta)) {
2404
+ if (key.startsWith(prefix)) {
2405
+ const keyEntry = meta[key];
2406
+ const keyHasThumbnails = keyEntry ? isProcessed(keyEntry) : false;
2407
+ if (keyEntry?.c !== void 0) {
2408
+ try {
2409
+ await deleteFromCdn(key, keyHasThumbnails);
2410
+ } catch {
2411
+ }
2412
+ }
2413
+ delete meta[key];
2414
+ foundAny = true;
2415
+ }
2416
+ }
2417
+ if (!foundAny) {
2418
+ errors.push(`Not found: ${itemPath}`);
2419
+ sendEvent({
2420
+ type: "progress",
2421
+ current: i + 1,
2422
+ total,
2423
+ deleted: deleted.length,
2424
+ percent: Math.round((i + 1) / total * 100),
2425
+ currentFile: path7.basename(itemPath)
2426
+ });
2427
+ continue;
2428
+ }
2429
+ }
2430
+ }
2431
+ await saveMeta(meta);
2432
+ deleted.push(itemPath);
2433
+ } catch (error) {
2434
+ console.error(`Failed to delete ${itemPath}:`, error);
2435
+ errors.push(itemPath);
2436
+ }
2437
+ sendEvent({
2438
+ type: "progress",
2439
+ current: i + 1,
2440
+ total,
2441
+ deleted: deleted.length,
2442
+ percent: Math.round((i + 1) / total * 100),
2443
+ currentFile: path7.basename(itemPath)
2444
+ });
2445
+ }
2446
+ for (const folder of sourceFolders) {
2447
+ await deleteEmptyFolders(folder);
2448
+ }
2449
+ if (operationId) clearCancelledOperation(operationId);
2450
+ sendEvent({
2451
+ type: "complete",
2452
+ deleted: deleted.length,
2453
+ errors: errors.length,
2454
+ errorMessages: errors.length > 0 ? errors : void 0
2455
+ });
2456
+ } catch (error) {
2457
+ console.error("Failed to delete:", error);
2458
+ sendEvent({ type: "error", message: "Failed to delete files" });
2459
+ } finally {
2460
+ controller.close();
2461
+ }
2462
+ }
2463
+ });
2464
+ return new Response(stream, {
2465
+ headers: {
2466
+ "Content-Type": "text/event-stream",
2467
+ "Cache-Control": "no-cache",
2468
+ "Connection": "keep-alive"
2469
+ }
2470
+ });
2471
+ }
2281
2472
  async function handleCreateFolder(request) {
2282
2473
  try {
2283
2474
  const { parentPath, name } = await request.json();
@@ -3795,6 +3986,7 @@ async function startServer(options) {
3795
3986
  app.post("/api/studio/cdns", wrapHandler(handleUpdateCdns));
3796
3987
  app.post("/api/studio/generate-favicon", wrapHandler(handleGenerateFavicon, true));
3797
3988
  app.post("/api/studio/delete", wrapHandler(handleDelete));
3989
+ app.post("/api/studio/delete-stream", wrapHandler(handleDeleteStream, true));
3798
3990
  app.use(express.static(join(workspace, "public")));
3799
3991
  const clientDir = resolve(__dirname, "../client");
3800
3992
  app.get("/", (req, res) => {