@gallop.software/studio 2.3.68 → 2.3.70
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/client/index.html
CHANGED
|
@@ -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-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-yYR0IQiU.js"></script>
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
17
17
|
<div id="root"></div>
|
package/dist/server/index.js
CHANGED
|
@@ -141,7 +141,6 @@ function getContentType(filePath) {
|
|
|
141
141
|
import { promises as fs2 } from "fs";
|
|
142
142
|
import path3 from "path";
|
|
143
143
|
import sharp from "sharp";
|
|
144
|
-
import { encode } from "blurhash";
|
|
145
144
|
var FULL_MAX_WIDTH = 2560;
|
|
146
145
|
var DEFAULT_SIZES = {
|
|
147
146
|
small: { width: 300, suffix: "-sm", key: "sm" },
|
|
@@ -201,8 +200,6 @@ async function processImage(buffer, imageKey) {
|
|
|
201
200
|
}
|
|
202
201
|
entry[key] = { w: maxWidth, h: newHeight };
|
|
203
202
|
}
|
|
204
|
-
const { data, info } = await sharp(buffer).resize(32, 32, { fit: "inside" }).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
205
|
-
entry.b = encode(new Uint8ClampedArray(data), info.width, info.height, 4, 4);
|
|
206
203
|
return entry;
|
|
207
204
|
}
|
|
208
205
|
|
|
@@ -3314,7 +3311,6 @@ async function handleMoveStream(request) {
|
|
|
3314
3311
|
import { promises as fs8 } from "fs";
|
|
3315
3312
|
import path8 from "path";
|
|
3316
3313
|
import sharp3 from "sharp";
|
|
3317
|
-
import { encode as encode2 } from "blurhash";
|
|
3318
3314
|
async function handleScanStream() {
|
|
3319
3315
|
const encoder = new TextEncoder();
|
|
3320
3316
|
const stream = new ReadableStream({
|
|
@@ -3421,16 +3417,13 @@ async function handleScanStream() {
|
|
|
3421
3417
|
if (isImage) {
|
|
3422
3418
|
const ext = path8.extname(relativePath).toLowerCase();
|
|
3423
3419
|
if (ext === ".svg") {
|
|
3424
|
-
meta[imageKey] = { o: { w: 0, h: 0 }
|
|
3420
|
+
meta[imageKey] = { o: { w: 0, h: 0 } };
|
|
3425
3421
|
} else {
|
|
3426
3422
|
try {
|
|
3427
3423
|
const buffer = await fs8.readFile(fullPath);
|
|
3428
3424
|
const metadata = await sharp3(buffer).metadata();
|
|
3429
|
-
const { data, info } = await sharp3(buffer).resize(32, 32, { fit: "inside" }).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
3430
|
-
const blurhash = encode2(new Uint8ClampedArray(data), info.width, info.height, 4, 4);
|
|
3431
3425
|
meta[imageKey] = {
|
|
3432
|
-
o: { w: metadata.width || 0, h: metadata.height || 0 }
|
|
3433
|
-
b: blurhash
|
|
3426
|
+
o: { w: metadata.width || 0, h: metadata.height || 0 }
|
|
3434
3427
|
};
|
|
3435
3428
|
} catch {
|
|
3436
3429
|
meta[imageKey] = { o: { w: 0, h: 0 } };
|
|
@@ -3632,7 +3625,6 @@ async function handleDeleteOrphans(request) {
|
|
|
3632
3625
|
|
|
3633
3626
|
// src/handlers/import.ts
|
|
3634
3627
|
import sharp4 from "sharp";
|
|
3635
|
-
import { encode as encode3 } from "blurhash";
|
|
3636
3628
|
function parseImageUrl(url) {
|
|
3637
3629
|
const parsed = new URL(url);
|
|
3638
3630
|
const base = `${parsed.protocol}//${parsed.host}`;
|
|
@@ -3646,11 +3638,8 @@ async function processRemoteImage(url) {
|
|
|
3646
3638
|
}
|
|
3647
3639
|
const buffer = Buffer.from(await response.arrayBuffer());
|
|
3648
3640
|
const metadata = await sharp4(buffer).metadata();
|
|
3649
|
-
const { data, info } = await sharp4(buffer).resize(32, 32, { fit: "inside" }).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
|
|
3650
|
-
const blurhash = encode3(new Uint8ClampedArray(data), info.width, info.height, 4, 4);
|
|
3651
3641
|
return {
|
|
3652
|
-
o: { w: metadata.width || 0, h: metadata.height || 0 }
|
|
3653
|
-
b: blurhash
|
|
3642
|
+
o: { w: metadata.width || 0, h: metadata.height || 0 }
|
|
3654
3643
|
};
|
|
3655
3644
|
}
|
|
3656
3645
|
async function handleImportUrls(request) {
|
|
@@ -3911,6 +3900,152 @@ async function handleGenerateFavicon(request) {
|
|
|
3911
3900
|
});
|
|
3912
3901
|
}
|
|
3913
3902
|
|
|
3903
|
+
// src/handlers/featured-image.ts
|
|
3904
|
+
import puppeteer from "puppeteer";
|
|
3905
|
+
import fs10 from "fs/promises";
|
|
3906
|
+
async function handleGenerateFeaturedImage(request) {
|
|
3907
|
+
const encoder = new TextEncoder();
|
|
3908
|
+
let customUrl;
|
|
3909
|
+
try {
|
|
3910
|
+
const body = await request.json();
|
|
3911
|
+
customUrl = body.url;
|
|
3912
|
+
} catch {
|
|
3913
|
+
}
|
|
3914
|
+
const stream = new ReadableStream({
|
|
3915
|
+
async start(controller) {
|
|
3916
|
+
const sendEvent = (data) => {
|
|
3917
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
|
|
3918
|
+
|
|
3919
|
+
`));
|
|
3920
|
+
};
|
|
3921
|
+
try {
|
|
3922
|
+
const packageJsonPath2 = getWorkspacePath("package.json");
|
|
3923
|
+
let projectName = "featured-image";
|
|
3924
|
+
let homepageUrl = customUrl || process.env.STUDIO_DEV_SITE_URL || "http://localhost:3000";
|
|
3925
|
+
try {
|
|
3926
|
+
const packageJsonContent = await fs10.readFile(packageJsonPath2, "utf8");
|
|
3927
|
+
const packageJson2 = JSON.parse(packageJsonContent);
|
|
3928
|
+
projectName = packageJson2.name || "featured-image";
|
|
3929
|
+
if (!customUrl && packageJson2.homepage) {
|
|
3930
|
+
homepageUrl = packageJson2.homepage;
|
|
3931
|
+
}
|
|
3932
|
+
} catch {
|
|
3933
|
+
}
|
|
3934
|
+
const outputPath = getPublicPath(`${projectName}.jpg`);
|
|
3935
|
+
const relativePath = `public/${projectName}.jpg`;
|
|
3936
|
+
sendEvent({
|
|
3937
|
+
type: "start",
|
|
3938
|
+
total: 3,
|
|
3939
|
+
projectName,
|
|
3940
|
+
url: homepageUrl,
|
|
3941
|
+
output: relativePath
|
|
3942
|
+
});
|
|
3943
|
+
sendEvent({
|
|
3944
|
+
type: "progress",
|
|
3945
|
+
current: 1,
|
|
3946
|
+
total: 3,
|
|
3947
|
+
percent: 33,
|
|
3948
|
+
message: "Launching browser..."
|
|
3949
|
+
});
|
|
3950
|
+
const browser = await puppeteer.launch({
|
|
3951
|
+
headless: true,
|
|
3952
|
+
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
3953
|
+
});
|
|
3954
|
+
try {
|
|
3955
|
+
sendEvent({
|
|
3956
|
+
type: "progress",
|
|
3957
|
+
current: 2,
|
|
3958
|
+
total: 3,
|
|
3959
|
+
percent: 66,
|
|
3960
|
+
message: `Navigating to ${homepageUrl}...`
|
|
3961
|
+
});
|
|
3962
|
+
const page = await browser.newPage();
|
|
3963
|
+
await page.setViewport({
|
|
3964
|
+
width: 2e3,
|
|
3965
|
+
height: 1e3,
|
|
3966
|
+
deviceScaleFactor: 2
|
|
3967
|
+
// Retina display quality
|
|
3968
|
+
});
|
|
3969
|
+
await page.goto(homepageUrl, {
|
|
3970
|
+
waitUntil: "networkidle2",
|
|
3971
|
+
timeout: 3e4
|
|
3972
|
+
});
|
|
3973
|
+
await new Promise((resolve2) => setTimeout(resolve2, 2e3));
|
|
3974
|
+
sendEvent({
|
|
3975
|
+
type: "progress",
|
|
3976
|
+
current: 3,
|
|
3977
|
+
total: 3,
|
|
3978
|
+
percent: 90,
|
|
3979
|
+
message: "Taking screenshot..."
|
|
3980
|
+
});
|
|
3981
|
+
await page.screenshot({
|
|
3982
|
+
path: outputPath,
|
|
3983
|
+
type: "jpeg",
|
|
3984
|
+
quality: 90
|
|
3985
|
+
});
|
|
3986
|
+
sendEvent({
|
|
3987
|
+
type: "complete",
|
|
3988
|
+
processed: 1,
|
|
3989
|
+
errors: 0,
|
|
3990
|
+
outputPath: relativePath,
|
|
3991
|
+
message: `Featured image saved to ${relativePath}`
|
|
3992
|
+
});
|
|
3993
|
+
} finally {
|
|
3994
|
+
await browser.close();
|
|
3995
|
+
}
|
|
3996
|
+
controller.close();
|
|
3997
|
+
} catch (error) {
|
|
3998
|
+
console.error("Featured image generation error:", error);
|
|
3999
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
4000
|
+
sendEvent({
|
|
4001
|
+
type: "error",
|
|
4002
|
+
message: `Failed to generate featured image: ${errorMessage}`
|
|
4003
|
+
});
|
|
4004
|
+
controller.close();
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
});
|
|
4008
|
+
return new Response(stream, {
|
|
4009
|
+
headers: {
|
|
4010
|
+
"Content-Type": "text/event-stream",
|
|
4011
|
+
"Cache-Control": "no-cache",
|
|
4012
|
+
Connection: "keep-alive"
|
|
4013
|
+
}
|
|
4014
|
+
});
|
|
4015
|
+
}
|
|
4016
|
+
async function handleCheckFeaturedImage() {
|
|
4017
|
+
try {
|
|
4018
|
+
const packageJsonPath2 = getWorkspacePath("package.json");
|
|
4019
|
+
let projectName = "featured-image";
|
|
4020
|
+
try {
|
|
4021
|
+
const packageJsonContent = await fs10.readFile(packageJsonPath2, "utf8");
|
|
4022
|
+
const packageJson2 = JSON.parse(packageJsonContent);
|
|
4023
|
+
projectName = packageJson2.name || "featured-image";
|
|
4024
|
+
} catch {
|
|
4025
|
+
}
|
|
4026
|
+
const expectedFilename = `${projectName}.jpg`;
|
|
4027
|
+
const expectedPath = getPublicPath(expectedFilename);
|
|
4028
|
+
let exists = false;
|
|
4029
|
+
try {
|
|
4030
|
+
await fs10.access(expectedPath);
|
|
4031
|
+
exists = true;
|
|
4032
|
+
} catch {
|
|
4033
|
+
exists = false;
|
|
4034
|
+
}
|
|
4035
|
+
return jsonResponse({
|
|
4036
|
+
filename: expectedFilename,
|
|
4037
|
+
exists,
|
|
4038
|
+
projectName
|
|
4039
|
+
});
|
|
4040
|
+
} catch (error) {
|
|
4041
|
+
console.error("Check featured image error:", error);
|
|
4042
|
+
return jsonResponse(
|
|
4043
|
+
{ error: "Failed to check featured image" },
|
|
4044
|
+
{ status: 500 }
|
|
4045
|
+
);
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
|
|
3914
4049
|
// src/server/index.ts
|
|
3915
4050
|
var __filename = fileURLToPath(import.meta.url);
|
|
3916
4051
|
var __dirname = dirname(__filename);
|
|
@@ -3937,7 +4072,9 @@ async function findAvailablePort(startPort, maxAttempts = 10) {
|
|
|
3937
4072
|
return port;
|
|
3938
4073
|
}
|
|
3939
4074
|
}
|
|
3940
|
-
throw new Error(
|
|
4075
|
+
throw new Error(
|
|
4076
|
+
`No available port found between ${startPort} and ${startPort + maxAttempts - 1}`
|
|
4077
|
+
);
|
|
3941
4078
|
}
|
|
3942
4079
|
async function startServer(options) {
|
|
3943
4080
|
const { port: requestedPort, workspace, open } = options;
|
|
@@ -3971,6 +4108,10 @@ async function startServer(options) {
|
|
|
3971
4108
|
app.get("/api/studio/count-images", wrapHandler(handleCountImages));
|
|
3972
4109
|
app.get("/api/studio/folder-images", wrapHandler(handleFolderImages));
|
|
3973
4110
|
app.get("/api/studio/cdns", wrapHandler(handleGetCdns));
|
|
4111
|
+
app.get(
|
|
4112
|
+
"/api/studio/check-featured-image",
|
|
4113
|
+
wrapHandler(handleCheckFeaturedImage)
|
|
4114
|
+
);
|
|
3974
4115
|
app.post("/api/studio/upload", wrapRawHandler(handleUpload));
|
|
3975
4116
|
app.post("/api/studio/create-folder", wrapHandler(handleCreateFolder));
|
|
3976
4117
|
app.post("/api/studio/rename", wrapHandler(handleRename));
|
|
@@ -3978,17 +4119,39 @@ async function startServer(options) {
|
|
|
3978
4119
|
app.post("/api/studio/move", wrapHandler(handleMoveStream, true));
|
|
3979
4120
|
app.post("/api/studio/sync", wrapHandler(handleSync, true));
|
|
3980
4121
|
app.post("/api/studio/sync-stream", wrapHandler(handleSyncStream, true));
|
|
3981
|
-
app.post(
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
4122
|
+
app.post(
|
|
4123
|
+
"/api/studio/reprocess-stream",
|
|
4124
|
+
wrapHandler(handleReprocessStream, true)
|
|
4125
|
+
);
|
|
4126
|
+
app.post(
|
|
4127
|
+
"/api/studio/unprocess-stream",
|
|
4128
|
+
wrapHandler(handleUnprocessStream, true)
|
|
4129
|
+
);
|
|
4130
|
+
app.post(
|
|
4131
|
+
"/api/studio/download-stream",
|
|
4132
|
+
wrapHandler(handleDownloadStream, true)
|
|
4133
|
+
);
|
|
4134
|
+
app.post(
|
|
4135
|
+
"/api/studio/push-updates-stream",
|
|
4136
|
+
wrapHandler(handlePushUpdatesStream, true)
|
|
4137
|
+
);
|
|
3985
4138
|
app.post("/api/studio/cancel-updates", wrapHandler(handleCancelUpdates));
|
|
3986
|
-
app.post(
|
|
4139
|
+
app.post(
|
|
4140
|
+
"/api/studio/cancel-stream",
|
|
4141
|
+
wrapHandler(handleCancelStreamOperation)
|
|
4142
|
+
);
|
|
3987
4143
|
app.post("/api/studio/scan", wrapHandler(handleScanStream, true));
|
|
3988
4144
|
app.post("/api/studio/delete-orphans", wrapHandler(handleDeleteOrphans));
|
|
3989
4145
|
app.post("/api/studio/import", wrapHandler(handleImportUrls, true));
|
|
3990
4146
|
app.post("/api/studio/cdns", wrapHandler(handleUpdateCdns));
|
|
3991
|
-
app.post(
|
|
4147
|
+
app.post(
|
|
4148
|
+
"/api/studio/generate-favicon",
|
|
4149
|
+
wrapHandler(handleGenerateFavicon, true)
|
|
4150
|
+
);
|
|
4151
|
+
app.post(
|
|
4152
|
+
"/api/studio/generate-featured-image",
|
|
4153
|
+
wrapHandler(handleGenerateFeaturedImage, true)
|
|
4154
|
+
);
|
|
3992
4155
|
app.post("/api/studio/delete", wrapHandler(handleDelete));
|
|
3993
4156
|
app.post("/api/studio/delete-stream", wrapHandler(handleDeleteStream, true));
|
|
3994
4157
|
app.use(express.static(join(workspace, "public")));
|