@cocreate/file-server 1.18.9 → 1.18.10
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 +7 -0
- package/package.json +1 -1
- package/src/index.js +82 -48
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [1.18.10](https://github.com/CoCreate-app/CoCreate-file-server/compare/v1.18.9...v1.18.10) (2025-11-17)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* enhance font and data URI handling in file processing ([25b7e8c](https://github.com/CoCreate-app/CoCreate-file-server/commit/25b7e8c1976c12ea99f1806025c248e0fa865ef0))
|
|
7
|
+
|
|
1
8
|
## [1.18.9](https://github.com/CoCreate-app/CoCreate-file-server/compare/v1.18.8...v1.18.9) (2025-10-11)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -217,48 +217,74 @@ class CoCreateFileSystem {
|
|
|
217
217
|
|
|
218
218
|
let contentType = file["content-type"] || "text/html";
|
|
219
219
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
220
|
+
// Normalize and decode src based on content-type and pathname.
|
|
221
|
+
async function normalizeSrc(src, contentType, pathname) {
|
|
222
|
+
const isBase64Only = (s) =>
|
|
223
|
+
typeof s === "string" && /^[A-Za-z0-9+/]+={0,2}$/.test(s) && s.length % 4 === 0;
|
|
224
|
+
|
|
225
|
+
const parseDataUri = (s) => {
|
|
226
|
+
// returns { mime, isBase64, data } or null
|
|
227
|
+
const m = /^data:([^;]+)(;base64)?,(.*)$/is.exec(s);
|
|
228
|
+
if (!m) return null;
|
|
229
|
+
return { mime: m[1].toLowerCase(), isBase64: !!m[2], data: m[3] };
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Fonts: data:font/...;base64 or plain base64 -> Buffer
|
|
233
|
+
if (contentType.startsWith("font/") || /\.(woff2?|ttf|otf)$/i.test(pathname)) {
|
|
234
|
+
if (Buffer.isBuffer(src)) return src;
|
|
235
|
+
if (typeof src !== "string") throw new Error("Invalid font src");
|
|
236
|
+
const d = parseDataUri(src);
|
|
237
|
+
if (d && d.isBase64) return Buffer.from(d.data, "base64");
|
|
238
|
+
// maybe stored as bare base64
|
|
239
|
+
if (isBase64Only(src)) return Buffer.from(src, "base64");
|
|
240
|
+
throw new Error("Font data is not valid base64 or data URI");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Data URIs
|
|
244
|
+
if (typeof src === "string") {
|
|
245
|
+
const d = parseDataUri(src);
|
|
246
|
+
if (d) {
|
|
247
|
+
// SVG: decode to utf8 string so browsers render SVG correctly
|
|
248
|
+
if (d.mime === "image/svg+xml") {
|
|
249
|
+
if (d.isBase64) return Buffer.from(d.data, "base64").toString("utf8");
|
|
250
|
+
// URI-encoded SVG payload
|
|
251
|
+
try {
|
|
252
|
+
return decodeURIComponent(d.data);
|
|
253
|
+
} catch (_) {
|
|
254
|
+
return d.data;
|
|
255
|
+
}
|
|
226
256
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
|
|
257
|
+
// Raster images -> Buffer
|
|
258
|
+
if (/^image\/(png|jpe?g|webp|bmp|gif)$/i.test(d.mime)) {
|
|
259
|
+
if (d.isBase64) return Buffer.from(d.data, "base64");
|
|
260
|
+
}
|
|
261
|
+
// If it's a text data URI (e.g., xml) and not base64, return decoded text
|
|
262
|
+
if (!d.isBase64) {
|
|
263
|
+
try {
|
|
264
|
+
return decodeURIComponent(d.data);
|
|
265
|
+
} catch (_) {
|
|
266
|
+
return d.data;
|
|
267
|
+
}
|
|
232
268
|
}
|
|
233
|
-
} else {
|
|
234
|
-
throw new Error("Font data is not a valid base64 string");
|
|
235
269
|
}
|
|
236
|
-
} catch (err) {
|
|
237
|
-
console.error("Error processing font file:", {
|
|
238
|
-
message: err.message,
|
|
239
|
-
contentType,
|
|
240
|
-
srcType: typeof src
|
|
241
|
-
});
|
|
242
|
-
let pageNotFound = await getDefaultFile("/404.html");
|
|
243
|
-
return sendResponse(pageNotFound.object[0].src, 404, {
|
|
244
|
-
"Content-Type": "text/html"
|
|
245
|
-
});
|
|
246
270
|
}
|
|
247
|
-
} else if (
|
|
248
|
-
/^data:image\/[a-zA-Z0-9+.-]+;base64,([A-Za-z0-9+/]+={0,2})$/.test(
|
|
249
|
-
src
|
|
250
|
-
)
|
|
251
|
-
) {
|
|
252
|
-
src = src.replace(/^data:image\/(png|jpeg|jpg);base64,/, "");
|
|
253
|
-
src = Buffer.from(src, "base64");
|
|
254
|
-
} else if (/^([A-Za-z0-9+/]+={0,2})$/.test(src)) {
|
|
255
|
-
src = Buffer.from(src, "base64");
|
|
256
|
-
} else if (contentType === "text/html") {
|
|
257
|
-
try {
|
|
258
|
-
let data = {};
|
|
259
271
|
|
|
260
|
-
|
|
261
|
-
|
|
272
|
+
// Plain base64-only string: decode to Buffer only for binary content types
|
|
273
|
+
if (isBase64Only(src)) {
|
|
274
|
+
if (
|
|
275
|
+
contentType.startsWith("image/") ||
|
|
276
|
+
contentType.startsWith("font/") ||
|
|
277
|
+
contentType === "application/octet-stream"
|
|
278
|
+
) {
|
|
279
|
+
return Buffer.from(src, "base64");
|
|
280
|
+
}
|
|
281
|
+
// textual content kept as-is
|
|
282
|
+
return src;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// HTML rendering
|
|
286
|
+
if (contentType === "text/html") {
|
|
287
|
+
return await this.render.HTML(
|
|
262
288
|
file,
|
|
263
289
|
organization,
|
|
264
290
|
urlObject,
|
|
@@ -266,20 +292,28 @@ class CoCreateFileSystem {
|
|
|
266
292
|
lang,
|
|
267
293
|
theme
|
|
268
294
|
);
|
|
269
|
-
} catch (err) {
|
|
270
|
-
console.warn("server-side-render: " + err.message);
|
|
271
295
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
contentType === "application/xml"
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
296
|
+
|
|
297
|
+
// XML host replacement if src is string
|
|
298
|
+
if ((contentType === "text/xml" || contentType === "application/xml") && typeof src === "string") {
|
|
299
|
+
const protocol = "https://";
|
|
300
|
+
return src.replaceAll("{{$host}}", `${protocol}${hostname}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Otherwise return as-is (string, Buffer, object)
|
|
304
|
+
return src;
|
|
281
305
|
}
|
|
282
306
|
|
|
307
|
+
try {
|
|
308
|
+
src = await normalizeSrc.call(this, src, contentType, pathname);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
console.error("Error processing file src:", err && err.message);
|
|
311
|
+
let pageNotFound = await getDefaultFile("/404.html");
|
|
312
|
+
return sendResponse(pageNotFound.object[0].src, 404, {
|
|
313
|
+
"Content-Type": "text/html"
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
|
|
283
317
|
sendResponse(src, 200, { "Content-Type": contentType });
|
|
284
318
|
this.sitemap.check(file, hostname);
|
|
285
319
|
|