@bacnh85/pi-web 0.10.3 → 0.10.4
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/CHANGELOG.md +8 -0
- package/extensions/lib/imageapi.ts +15 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.4 (2026-09-13)
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Truthful image extensions**: saved files are typed by magic bytes, not
|
|
8
|
+
URL/file extension — Z.ai GLM-Image serves JPEG behind a `.png` URL, which
|
|
9
|
+
previously produced mislabeled files and inline blocks.
|
|
10
|
+
|
|
3
11
|
## 0.10.3 (2026-09-13)
|
|
4
12
|
|
|
5
13
|
### Fixed
|
|
@@ -238,7 +238,7 @@ export async function apiGenerateImage(opts: {
|
|
|
238
238
|
for (let i = 0; i < items.length; i++) {
|
|
239
239
|
const item = items[i];
|
|
240
240
|
if (typeof item?.b64_json === "string" && item.b64_json) {
|
|
241
|
-
paths.push(writeB64(opts.outDir, item.b64_json, i));
|
|
241
|
+
paths.push(writeB64(opts.outDir, Buffer.from(item.b64_json, "base64"), i));
|
|
242
242
|
} else if (typeof item?.url === "string" && item.url) {
|
|
243
243
|
// A failed download must not waste the generation: surface the URL.
|
|
244
244
|
try {
|
|
@@ -256,9 +256,19 @@ export async function apiGenerateImage(opts: {
|
|
|
256
256
|
return { paths, urls, model: typeof payload?.model === "string" ? payload.model : opts.model };
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
// Some gateways serve JPEG/WebP bytes behind a .png URL (Z.ai GLM-Image does) —
|
|
260
|
+
// trust the magic bytes, not the URL/file extension.
|
|
261
|
+
function extFromBytes(buf: Buffer, fallback: string): string {
|
|
262
|
+
if (buf.length >= 4 && buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) return ".png";
|
|
263
|
+
if (buf.length >= 3 && buf[0] === 0xff && buf[1] === 0xd8 && buf[2] === 0xff) return ".jpg";
|
|
264
|
+
if (buf.length >= 6 && buf.toString("ascii", 0, 3) === "GIF") return ".gif";
|
|
265
|
+
if (buf.length >= 12 && buf.toString("ascii", 0, 4) === "RIFF" && buf.toString("ascii", 8, 12) === "WEBP") return ".webp";
|
|
266
|
+
return fallback;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function writeB64(outDir: string, buf: Buffer, i: number): string {
|
|
270
|
+
const file = path.join(outDir, `pi-web-image-${randomUUID().slice(0, 8)}-${i}${extFromBytes(buf, ".png")}`);
|
|
271
|
+
fs.writeFileSync(file, buf);
|
|
262
272
|
return file;
|
|
263
273
|
}
|
|
264
274
|
|
|
@@ -290,7 +300,7 @@ async function downloadImage(
|
|
|
290
300
|
if (!res.ok) throw new ImageApiError(res.status, `image download failed (HTTP ${res.status})`);
|
|
291
301
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
292
302
|
if (buf.length > MAX_DOWNLOAD_BYTES) throw new Error(`image exceeds the ${MAX_DOWNLOAD_BYTES}-byte download cap`);
|
|
293
|
-
const file = path.join(outDir, `pi-web-image-${randomUUID().slice(0, 8)}-${i}${extFor(url)}`);
|
|
303
|
+
const file = path.join(outDir, `pi-web-image-${randomUUID().slice(0, 8)}-${i}${extFromBytes(buf, extFor(url))}`);
|
|
294
304
|
fs.writeFileSync(file, buf);
|
|
295
305
|
return file;
|
|
296
306
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bacnh85/pi-web",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4",
|
|
4
4
|
"description": "Pi extension for web search, page extraction, Firecrawl scraping/crawling, Crawl4AI headless browser crawling, Gemini web-tier research, free upstream image generation, and one-off gateway chat.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|