@gallop.software/studio 1.4.7 → 1.5.1
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-TP2Y3ZEL.mjs → StudioUI-BHFZVR57.mjs} +118 -1
- package/dist/StudioUI-BHFZVR57.mjs.map +1 -0
- package/dist/{StudioUI-FROMYB7Y.js → StudioUI-GULMXZQF.js} +124 -7
- package/dist/StudioUI-GULMXZQF.js.map +1 -0
- package/dist/handlers/index.js +122 -7
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/index.mjs +128 -13
- 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-FROMYB7Y.js.map +0 -1
- package/dist/StudioUI-TP2Y3ZEL.mjs.map +0 -1
package/dist/handlers/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "../chunk-VQJAJVAQ.mjs";
|
|
6
6
|
|
|
7
7
|
// src/handlers/index.ts
|
|
8
|
-
import { NextResponse as
|
|
8
|
+
import { NextResponse as NextResponse6 } from "next/server";
|
|
9
9
|
|
|
10
10
|
// src/handlers/list.ts
|
|
11
11
|
import { NextResponse } from "next/server";
|
|
@@ -2085,8 +2085,8 @@ import { encode as encode3 } from "blurhash";
|
|
|
2085
2085
|
function parseImageUrl(url) {
|
|
2086
2086
|
const parsed = new URL(url);
|
|
2087
2087
|
const base = `${parsed.protocol}//${parsed.host}`;
|
|
2088
|
-
const
|
|
2089
|
-
return { base, path:
|
|
2088
|
+
const path10 = parsed.pathname;
|
|
2089
|
+
return { base, path: path10 };
|
|
2090
2090
|
}
|
|
2091
2091
|
async function processRemoteImage(url) {
|
|
2092
2092
|
const response = await fetch(url);
|
|
@@ -2135,20 +2135,20 @@ async function handleImportUrls(request) {
|
|
|
2135
2135
|
currentFile: url
|
|
2136
2136
|
});
|
|
2137
2137
|
try {
|
|
2138
|
-
const { base, path:
|
|
2139
|
-
const existingEntry = getMetaEntry(meta,
|
|
2138
|
+
const { base, path: path10 } = parseImageUrl(url);
|
|
2139
|
+
const existingEntry = getMetaEntry(meta, path10);
|
|
2140
2140
|
if (existingEntry) {
|
|
2141
|
-
skipped.push(
|
|
2141
|
+
skipped.push(path10);
|
|
2142
2142
|
continue;
|
|
2143
2143
|
}
|
|
2144
2144
|
const cdnIndex = getOrAddCdnIndex(meta, base);
|
|
2145
2145
|
const imageData = await processRemoteImage(url);
|
|
2146
|
-
setMetaEntry(meta,
|
|
2146
|
+
setMetaEntry(meta, path10, {
|
|
2147
2147
|
o: imageData.o,
|
|
2148
2148
|
b: imageData.b,
|
|
2149
2149
|
c: cdnIndex
|
|
2150
2150
|
});
|
|
2151
|
-
added.push(
|
|
2151
|
+
added.push(path10);
|
|
2152
2152
|
} catch (error) {
|
|
2153
2153
|
console.error(`Failed to import ${url}:`, error);
|
|
2154
2154
|
errors.push(url);
|
|
@@ -2203,10 +2203,122 @@ async function handleUpdateCdns(request) {
|
|
|
2203
2203
|
}
|
|
2204
2204
|
}
|
|
2205
2205
|
|
|
2206
|
+
// src/handlers/favicon.ts
|
|
2207
|
+
import { NextResponse as NextResponse5 } from "next/server";
|
|
2208
|
+
import sharp5 from "sharp";
|
|
2209
|
+
import path9 from "path";
|
|
2210
|
+
import fs8 from "fs/promises";
|
|
2211
|
+
var FAVICON_CONFIGS = [
|
|
2212
|
+
{ name: "favicon.ico", size: 48 },
|
|
2213
|
+
{ name: "icon.png", size: 32 },
|
|
2214
|
+
{ name: "apple-icon.png", size: 180 }
|
|
2215
|
+
];
|
|
2216
|
+
async function handleGenerateFavicon(request) {
|
|
2217
|
+
const encoder = new TextEncoder();
|
|
2218
|
+
let imagePath;
|
|
2219
|
+
try {
|
|
2220
|
+
const body = await request.json();
|
|
2221
|
+
imagePath = body.imagePath;
|
|
2222
|
+
if (!imagePath) {
|
|
2223
|
+
return NextResponse5.json({ error: "No image path provided" }, { status: 400 });
|
|
2224
|
+
}
|
|
2225
|
+
} catch {
|
|
2226
|
+
return NextResponse5.json({ error: "Invalid request body" }, { status: 400 });
|
|
2227
|
+
}
|
|
2228
|
+
const fileName = path9.basename(imagePath).toLowerCase();
|
|
2229
|
+
if (fileName !== "favicon.png" && fileName !== "favicon.jpg") {
|
|
2230
|
+
return NextResponse5.json({
|
|
2231
|
+
error: "Source file must be named favicon.png or favicon.jpg"
|
|
2232
|
+
}, { status: 400 });
|
|
2233
|
+
}
|
|
2234
|
+
const sourcePath = path9.join(process.cwd(), "public", imagePath.replace(/^\//, ""));
|
|
2235
|
+
try {
|
|
2236
|
+
await fs8.access(sourcePath);
|
|
2237
|
+
} catch {
|
|
2238
|
+
return NextResponse5.json({ error: "Source file not found" }, { status: 404 });
|
|
2239
|
+
}
|
|
2240
|
+
let metadata;
|
|
2241
|
+
try {
|
|
2242
|
+
metadata = await sharp5(sourcePath).metadata();
|
|
2243
|
+
} catch {
|
|
2244
|
+
return NextResponse5.json({ error: "Source file is not a valid image" }, { status: 400 });
|
|
2245
|
+
}
|
|
2246
|
+
const outputDir = path9.join(process.cwd(), "src", "app");
|
|
2247
|
+
try {
|
|
2248
|
+
await fs8.access(outputDir);
|
|
2249
|
+
} catch {
|
|
2250
|
+
return NextResponse5.json({
|
|
2251
|
+
error: "Output directory src/app/ not found"
|
|
2252
|
+
}, { status: 500 });
|
|
2253
|
+
}
|
|
2254
|
+
const stream = new ReadableStream({
|
|
2255
|
+
async start(controller) {
|
|
2256
|
+
const sendEvent = (data) => {
|
|
2257
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
2258
|
+
|
|
2259
|
+
`));
|
|
2260
|
+
};
|
|
2261
|
+
try {
|
|
2262
|
+
const total = FAVICON_CONFIGS.length;
|
|
2263
|
+
const generated = [];
|
|
2264
|
+
const errors = [];
|
|
2265
|
+
sendEvent({
|
|
2266
|
+
type: "start",
|
|
2267
|
+
total,
|
|
2268
|
+
sourceSize: `${metadata.width}x${metadata.height}`
|
|
2269
|
+
});
|
|
2270
|
+
for (let i = 0; i < FAVICON_CONFIGS.length; i++) {
|
|
2271
|
+
const config = FAVICON_CONFIGS[i];
|
|
2272
|
+
sendEvent({
|
|
2273
|
+
type: "progress",
|
|
2274
|
+
current: i + 1,
|
|
2275
|
+
total,
|
|
2276
|
+
percent: Math.round((i + 1) / total * 100),
|
|
2277
|
+
message: `Generating ${config.name} (${config.size}x${config.size})...`
|
|
2278
|
+
});
|
|
2279
|
+
try {
|
|
2280
|
+
const outputPath = path9.join(outputDir, config.name);
|
|
2281
|
+
await sharp5(sourcePath).resize(config.size, config.size, {
|
|
2282
|
+
fit: "cover",
|
|
2283
|
+
position: "center"
|
|
2284
|
+
}).png({ quality: 100 }).toFile(outputPath);
|
|
2285
|
+
generated.push(config.name);
|
|
2286
|
+
} catch (error) {
|
|
2287
|
+
console.error(`Failed to generate ${config.name}:`, error);
|
|
2288
|
+
errors.push(config.name);
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
let message = `Generated ${generated.length} favicon${generated.length !== 1 ? "s" : ""} to src/app/.`;
|
|
2292
|
+
if (errors.length > 0) {
|
|
2293
|
+
message += ` ${errors.length} failed.`;
|
|
2294
|
+
}
|
|
2295
|
+
sendEvent({
|
|
2296
|
+
type: "complete",
|
|
2297
|
+
processed: generated.length,
|
|
2298
|
+
errors: errors.length,
|
|
2299
|
+
message
|
|
2300
|
+
});
|
|
2301
|
+
controller.close();
|
|
2302
|
+
} catch (error) {
|
|
2303
|
+
console.error("Favicon generation error:", error);
|
|
2304
|
+
sendEvent({ type: "error", message: "Failed to generate favicons" });
|
|
2305
|
+
controller.close();
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
});
|
|
2309
|
+
return new Response(stream, {
|
|
2310
|
+
headers: {
|
|
2311
|
+
"Content-Type": "text/event-stream",
|
|
2312
|
+
"Cache-Control": "no-cache",
|
|
2313
|
+
Connection: "keep-alive"
|
|
2314
|
+
}
|
|
2315
|
+
});
|
|
2316
|
+
}
|
|
2317
|
+
|
|
2206
2318
|
// src/handlers/index.ts
|
|
2207
2319
|
async function GET(request) {
|
|
2208
2320
|
if (process.env.NODE_ENV !== "development") {
|
|
2209
|
-
return
|
|
2321
|
+
return NextResponse6.json({ error: "Not available in production" }, { status: 403 });
|
|
2210
2322
|
}
|
|
2211
2323
|
const pathname = request.nextUrl.pathname;
|
|
2212
2324
|
const route = pathname.replace(/^\/api\/studio\/?/, "");
|
|
@@ -2228,11 +2340,11 @@ async function GET(request) {
|
|
|
2228
2340
|
if (route === "cdns") {
|
|
2229
2341
|
return handleGetCdns();
|
|
2230
2342
|
}
|
|
2231
|
-
return
|
|
2343
|
+
return NextResponse6.json({ error: "Not found" }, { status: 404 });
|
|
2232
2344
|
}
|
|
2233
2345
|
async function POST(request) {
|
|
2234
2346
|
if (process.env.NODE_ENV !== "development") {
|
|
2235
|
-
return
|
|
2347
|
+
return NextResponse6.json({ error: "Not available in production" }, { status: 403 });
|
|
2236
2348
|
}
|
|
2237
2349
|
const pathname = request.nextUrl.pathname;
|
|
2238
2350
|
const route = pathname.replace(/^\/api\/studio\/?/, "");
|
|
@@ -2278,11 +2390,14 @@ async function POST(request) {
|
|
|
2278
2390
|
if (route === "cdns") {
|
|
2279
2391
|
return handleUpdateCdns(request);
|
|
2280
2392
|
}
|
|
2281
|
-
|
|
2393
|
+
if (route === "generate-favicon") {
|
|
2394
|
+
return handleGenerateFavicon(request);
|
|
2395
|
+
}
|
|
2396
|
+
return NextResponse6.json({ error: "Not found" }, { status: 404 });
|
|
2282
2397
|
}
|
|
2283
2398
|
async function DELETE(request) {
|
|
2284
2399
|
if (process.env.NODE_ENV !== "development") {
|
|
2285
|
-
return
|
|
2400
|
+
return NextResponse6.json({ error: "Not available in production" }, { status: 403 });
|
|
2286
2401
|
}
|
|
2287
2402
|
return handleDelete(request);
|
|
2288
2403
|
}
|