@plasius/images 1.0.0 → 1.0.2
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 +31 -1
- package/dist/index.cjs +225 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -2
- package/dist/index.js +186 -1
- package/dist/index.js.map +1 -0
- package/docs/adrs/index.md +4 -0
- package/package.json +17 -16
- package/dist/detectFormat.d.ts +0 -2
- package/dist/detectFormat.d.ts.map +0 -1
- package/dist/detectFormat.js +0 -20
- package/dist/index.d.ts.map +0 -1
- package/dist/parse/index.d.ts +0 -5
- package/dist/parse/index.d.ts.map +0 -1
- package/dist/parse/index.js +0 -4
- package/dist/parse/parseJpeg.d.ts +0 -5
- package/dist/parse/parseJpeg.d.ts.map +0 -1
- package/dist/parse/parseJpeg.js +0 -18
- package/dist/parse/parsePng.d.ts +0 -5
- package/dist/parse/parsePng.d.ts.map +0 -1
- package/dist/parse/parsePng.js +0 -6
- package/dist/parse/parseSVG.d.ts +0 -5
- package/dist/parse/parseSVG.d.ts.map +0 -1
- package/dist/parse/parseSVG.js +0 -23
- package/dist/parse/parseWebp.d.ts +0 -5
- package/dist/parse/parseWebp.d.ts.map +0 -1
- package/dist/parse/parseWebp.js +0 -17
- package/dist/validators/avatarValidator.d.ts +0 -9
- package/dist/validators/avatarValidator.d.ts.map +0 -1
- package/dist/validators/avatarValidator.js +0 -51
- package/dist/validators/index.d.ts +0 -3
- package/dist/validators/index.d.ts.map +0 -1
- package/dist/validators/index.js +0 -2
- package/dist/validators/svgValidator.d.ts +0 -18
- package/dist/validators/svgValidator.d.ts.map +0 -1
- package/dist/validators/svgValidator.js +0 -139
- package/dist-cjs/detectFormat.d.ts +0 -2
- package/dist-cjs/detectFormat.d.ts.map +0 -1
- package/dist-cjs/detectFormat.js +0 -23
- package/dist-cjs/index.d.ts +0 -2
- package/dist-cjs/index.d.ts.map +0 -1
- package/dist-cjs/index.js +0 -17
- package/dist-cjs/parse/index.d.ts +0 -5
- package/dist-cjs/parse/index.d.ts.map +0 -1
- package/dist-cjs/parse/index.js +0 -20
- package/dist-cjs/parse/parseJpeg.d.ts +0 -5
- package/dist-cjs/parse/parseJpeg.d.ts.map +0 -1
- package/dist-cjs/parse/parseJpeg.js +0 -21
- package/dist-cjs/parse/parsePng.d.ts +0 -5
- package/dist-cjs/parse/parsePng.d.ts.map +0 -1
- package/dist-cjs/parse/parsePng.js +0 -9
- package/dist-cjs/parse/parseSVG.d.ts +0 -5
- package/dist-cjs/parse/parseSVG.d.ts.map +0 -1
- package/dist-cjs/parse/parseSVG.js +0 -26
- package/dist-cjs/parse/parseWebp.d.ts +0 -5
- package/dist-cjs/parse/parseWebp.d.ts.map +0 -1
- package/dist-cjs/parse/parseWebp.js +0 -20
- package/dist-cjs/validators/avatarValidator.d.ts +0 -9
- package/dist-cjs/validators/avatarValidator.d.ts.map +0 -1
- package/dist-cjs/validators/avatarValidator.js +0 -57
- package/dist-cjs/validators/index.d.ts +0 -3
- package/dist-cjs/validators/index.d.ts.map +0 -1
- package/dist-cjs/validators/index.js +0 -18
- package/dist-cjs/validators/svgValidator.d.ts +0 -18
- package/dist-cjs/validators/svgValidator.d.ts.map +0 -1
- package/dist-cjs/validators/svgValidator.js +0 -143
package/dist/detectFormat.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export function detectFormat(buffer) {
|
|
2
|
-
if (buffer[0] === 0xff && buffer[1] === 0xd8) {
|
|
3
|
-
return "jpeg";
|
|
4
|
-
}
|
|
5
|
-
if (buffer[0] === 0x89 &&
|
|
6
|
-
buffer[1] === 0x50 &&
|
|
7
|
-
buffer[2] === 0x4e &&
|
|
8
|
-
buffer[3] === 0x47) {
|
|
9
|
-
return "png";
|
|
10
|
-
}
|
|
11
|
-
if (buffer.slice(0, 4).toString() === "RIFF" &&
|
|
12
|
-
buffer.slice(8, 12).toString() === "WEBP") {
|
|
13
|
-
return "webp";
|
|
14
|
-
}
|
|
15
|
-
const header = buffer.slice(0, 1000).toString("utf8").toLowerCase();
|
|
16
|
-
if (header.includes("<svg")) {
|
|
17
|
-
return "svg";
|
|
18
|
-
}
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
|
package/dist/parse/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parse/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
|
package/dist/parse/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseJpeg.d.ts","sourceRoot":"","sources":["../../src/parse/parseJpeg.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAqB3E"}
|
package/dist/parse/parseJpeg.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export function parseJpeg(buffer) {
|
|
2
|
-
let offset = 2;
|
|
3
|
-
while (offset < buffer.length) {
|
|
4
|
-
if (buffer[offset] !== 0xff) {
|
|
5
|
-
throw new Error("Invalid JPEG marker");
|
|
6
|
-
}
|
|
7
|
-
const marker = buffer[offset + 1];
|
|
8
|
-
const length = buffer.readUInt16BE(offset + 2);
|
|
9
|
-
// SOF0 (baseline), SOF2 (progressive)
|
|
10
|
-
if (marker === 0xc0 || marker === 0xc2) {
|
|
11
|
-
const height = buffer.readUInt16BE(offset + 5);
|
|
12
|
-
const width = buffer.readUInt16BE(offset + 7);
|
|
13
|
-
return { width, height };
|
|
14
|
-
}
|
|
15
|
-
offset += 2 + length;
|
|
16
|
-
}
|
|
17
|
-
throw new Error("JPEG SOF marker not found");
|
|
18
|
-
}
|
package/dist/parse/parsePng.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parsePng.d.ts","sourceRoot":"","sources":["../../src/parse/parsePng.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAKA"}
|
package/dist/parse/parsePng.js
DELETED
package/dist/parse/parseSVG.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseSVG.d.ts","sourceRoot":"","sources":["../../src/parse/parseSVG.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CA0BA"}
|
package/dist/parse/parseSVG.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export function parseSvg(buffer) {
|
|
2
|
-
const text = buffer.toString("utf8");
|
|
3
|
-
const matchViewBox = /viewBox\s*=\s*"([^"]+)"/i.exec(text);
|
|
4
|
-
const matchWidth = /width\s*=\s*"(\d+)(px)?"/i.exec(text);
|
|
5
|
-
const matchHeight = /height\s*=\s*"(\d+)(px)?"/i.exec(text);
|
|
6
|
-
let width;
|
|
7
|
-
let height;
|
|
8
|
-
if (matchWidth && matchHeight) {
|
|
9
|
-
width = parseInt(matchWidth[1], 10);
|
|
10
|
-
height = parseInt(matchHeight[1], 10);
|
|
11
|
-
}
|
|
12
|
-
else if (matchViewBox) {
|
|
13
|
-
const parts = matchViewBox[1].split(/\s+/);
|
|
14
|
-
if (parts.length === 4) {
|
|
15
|
-
width = parseFloat(parts[2]);
|
|
16
|
-
height = parseFloat(parts[3]);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
if (!width || !height) {
|
|
20
|
-
throw new Error("Could not determine SVG dimensions");
|
|
21
|
-
}
|
|
22
|
-
return { width, height };
|
|
23
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseWebp.d.ts","sourceRoot":"","sources":["../../src/parse/parseWebp.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAeA"}
|
package/dist/parse/parseWebp.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export function parseWebp(buffer) {
|
|
2
|
-
const chunkHeader = buffer.slice(12, 16).toString();
|
|
3
|
-
if (chunkHeader === "VP8X") {
|
|
4
|
-
const width = 1 + buffer.readUIntLE(24, 3);
|
|
5
|
-
const height = 1 + buffer.readUIntLE(27, 3);
|
|
6
|
-
return { width, height };
|
|
7
|
-
}
|
|
8
|
-
else if (chunkHeader === "VP8 ") {
|
|
9
|
-
// Simple lossless: parse frame header
|
|
10
|
-
const width = buffer.readUInt16LE(26) & 0x3fff;
|
|
11
|
-
const height = buffer.readUInt16LE(28) & 0x3fff;
|
|
12
|
-
return { width, height };
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
throw new Error("Unsupported WEBP chunk type: " + chunkHeader);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export interface ImageValidationResult {
|
|
2
|
-
width: number;
|
|
3
|
-
height: number;
|
|
4
|
-
format: string;
|
|
5
|
-
size: number;
|
|
6
|
-
safeBuffer: Buffer;
|
|
7
|
-
}
|
|
8
|
-
export declare function validateAvatarImage(buffer: Buffer): Promise<ImageValidationResult>;
|
|
9
|
-
//# sourceMappingURL=avatarValidator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"avatarValidator.d.ts","sourceRoot":"","sources":["../../src/validators/avatarValidator.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,qBAAqB,CAAC,CA0DhC"}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import sharp from "sharp";
|
|
2
|
-
import { validateSvgAvatar } from "./svgValidator.js";
|
|
3
|
-
export async function validateAvatarImage(buffer) {
|
|
4
|
-
const metadata = await sharp(buffer).metadata();
|
|
5
|
-
const format = metadata.format;
|
|
6
|
-
if (!format) {
|
|
7
|
-
throw new Error("Unsupported or unknown image format");
|
|
8
|
-
}
|
|
9
|
-
const width = metadata.width;
|
|
10
|
-
const height = metadata.height;
|
|
11
|
-
if (!width || !height) {
|
|
12
|
-
throw new Error("Could not determine image dimensions");
|
|
13
|
-
}
|
|
14
|
-
if (width < 64 || height < 64) {
|
|
15
|
-
throw new Error("Image too small (min 64x64)");
|
|
16
|
-
}
|
|
17
|
-
if (width > 2048 || height > 2048) {
|
|
18
|
-
throw new Error("Image too large (max 2048x2048)");
|
|
19
|
-
}
|
|
20
|
-
const targetFormat = "png"; // common safe web format
|
|
21
|
-
let safeBuffer;
|
|
22
|
-
if (format === "svg") {
|
|
23
|
-
const svgText = buffer.toString("utf8");
|
|
24
|
-
const svgValidation = await validateSvgAvatar(Buffer.from(svgText, "utf-8"));
|
|
25
|
-
safeBuffer = await sharp(svgValidation.safeBuffer)
|
|
26
|
-
.resize({
|
|
27
|
-
width: Math.min(width, 2048),
|
|
28
|
-
height: Math.min(height, 2048),
|
|
29
|
-
fit: "inside",
|
|
30
|
-
})
|
|
31
|
-
.toFormat(targetFormat)
|
|
32
|
-
.toBuffer();
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
safeBuffer = await sharp(buffer)
|
|
36
|
-
.resize({
|
|
37
|
-
width: Math.min(width, 2048),
|
|
38
|
-
height: Math.min(height, 2048),
|
|
39
|
-
fit: "inside",
|
|
40
|
-
})
|
|
41
|
-
.toFormat(targetFormat, { quality: 90 })
|
|
42
|
-
.toBuffer();
|
|
43
|
-
}
|
|
44
|
-
return {
|
|
45
|
-
width,
|
|
46
|
-
height,
|
|
47
|
-
format,
|
|
48
|
-
size: buffer.length,
|
|
49
|
-
safeBuffer,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validators/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC"}
|
package/dist/validators/index.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { ImageValidationResult } from "./avatarValidator.js";
|
|
2
|
-
export declare function sanitiseSVG(svgText: string, options: {
|
|
3
|
-
allowedTags: string[];
|
|
4
|
-
allowedAttributes: {
|
|
5
|
-
"*": string[];
|
|
6
|
-
};
|
|
7
|
-
allowComments: boolean;
|
|
8
|
-
allowUnknownElements: boolean;
|
|
9
|
-
allowUnknownAttributes: boolean;
|
|
10
|
-
}): {
|
|
11
|
-
svg: string;
|
|
12
|
-
audit: {
|
|
13
|
-
strippedTags: string[];
|
|
14
|
-
strippedAttributes: string[];
|
|
15
|
-
};
|
|
16
|
-
};
|
|
17
|
-
export declare function validateSvgAvatar(buffer: Buffer): Promise<ImageValidationResult>;
|
|
18
|
-
//# sourceMappingURL=svgValidator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"svgValidator.d.ts","sourceRoot":"","sources":["../../src/validators/svgValidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIlE,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IACP,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,EAAE;QAAE,GAAG,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACrC,aAAa,EAAE,OAAO,CAAC;IACvB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,sBAAsB,EAAE,OAAO,CAAC;CACjC,GACA;IACD,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE;QAAE,YAAY,EAAE,MAAM,EAAE,CAAC;QAAC,kBAAkB,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CACjE,CA+FA;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,qBAAqB,CAAC,CAkEhC"}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { DOMParser, XMLSerializer } from "@xmldom/xmldom";
|
|
2
|
-
export function sanitiseSVG(svgText, options) {
|
|
3
|
-
const strippedTags = [];
|
|
4
|
-
const strippedAttributes = [];
|
|
5
|
-
const parser = new DOMParser({
|
|
6
|
-
onError: (level, msg) => {
|
|
7
|
-
switch (level) {
|
|
8
|
-
case "warning":
|
|
9
|
-
break;
|
|
10
|
-
default:
|
|
11
|
-
throw new Error(msg);
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
});
|
|
15
|
-
const serializer = new XMLSerializer();
|
|
16
|
-
const doc = parser.parseFromString(svgText, "image/svg+xml");
|
|
17
|
-
function cleanNode(node) {
|
|
18
|
-
// TODO: optionally sanitize <style> elements and inline style attributes
|
|
19
|
-
if (node === null)
|
|
20
|
-
return;
|
|
21
|
-
if (node.nodeType === 8 /* Comment */ && !options.allowComments) {
|
|
22
|
-
node.parentNode?.removeChild(node);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
if (node.nodeType === 1 /* Element */) {
|
|
26
|
-
const el = node;
|
|
27
|
-
const tagName = el.tagName.toLowerCase();
|
|
28
|
-
// Strip <style> elements entirely
|
|
29
|
-
if (tagName === "style") {
|
|
30
|
-
strippedTags.push(tagName);
|
|
31
|
-
node.parentNode?.removeChild(node);
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
if (!options.allowedTags.includes(tagName) &&
|
|
35
|
-
!options.allowUnknownElements) {
|
|
36
|
-
strippedTags.push(tagName);
|
|
37
|
-
node.parentNode?.removeChild(node);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
// Clean attributes
|
|
41
|
-
const allowedAttrs = options.allowedAttributes["*"] || [];
|
|
42
|
-
const toRemove = [];
|
|
43
|
-
for (const attr of Array.from(el.attributes)) {
|
|
44
|
-
const attrName = attr.name.toLowerCase();
|
|
45
|
-
if (attrName.startsWith("on")) {
|
|
46
|
-
toRemove.push(attr.name);
|
|
47
|
-
strippedAttributes.push(`${tagName}.${attr.name}`);
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (attrName === "xlink:href" || attrName === "xmlns:xlink") {
|
|
51
|
-
toRemove.push(attr.name);
|
|
52
|
-
strippedAttributes.push(`${tagName}.${attr.name}`);
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
if (attrName === "style") {
|
|
56
|
-
toRemove.push(attr.name);
|
|
57
|
-
strippedAttributes.push(`${tagName}.${attr.name}`);
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
if (!allowedAttrs.includes(attr.name) &&
|
|
61
|
-
!options.allowUnknownAttributes) {
|
|
62
|
-
toRemove.push(attr.name);
|
|
63
|
-
strippedAttributes.push(`${tagName}.${attr.name}`);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
toRemove.forEach((attrName) => el.removeAttribute(attrName));
|
|
67
|
-
}
|
|
68
|
-
// Recursively clean children
|
|
69
|
-
const children = Array.from(node.childNodes);
|
|
70
|
-
children.forEach((child) => cleanNode(child));
|
|
71
|
-
}
|
|
72
|
-
cleanNode(doc.documentElement);
|
|
73
|
-
return {
|
|
74
|
-
svg: serializer.serializeToString(doc),
|
|
75
|
-
audit: { strippedTags, strippedAttributes },
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
export function validateSvgAvatar(buffer) {
|
|
79
|
-
const svgText = buffer.toString("utf8");
|
|
80
|
-
const { svg: cleanSvg } = sanitiseSVG(svgText, {
|
|
81
|
-
allowedTags: [
|
|
82
|
-
"svg",
|
|
83
|
-
"g",
|
|
84
|
-
"rect",
|
|
85
|
-
"circle",
|
|
86
|
-
"ellipse",
|
|
87
|
-
"line",
|
|
88
|
-
"polygon",
|
|
89
|
-
"polyline",
|
|
90
|
-
"path",
|
|
91
|
-
"text",
|
|
92
|
-
"title",
|
|
93
|
-
"desc",
|
|
94
|
-
],
|
|
95
|
-
allowedAttributes: {
|
|
96
|
-
"*": [
|
|
97
|
-
"width",
|
|
98
|
-
"height",
|
|
99
|
-
"viewBox",
|
|
100
|
-
"xmlns",
|
|
101
|
-
"transform",
|
|
102
|
-
"x",
|
|
103
|
-
"y",
|
|
104
|
-
"cx",
|
|
105
|
-
"cy",
|
|
106
|
-
"r",
|
|
107
|
-
"rx",
|
|
108
|
-
"ry",
|
|
109
|
-
"x1",
|
|
110
|
-
"y1",
|
|
111
|
-
"x2",
|
|
112
|
-
"y2",
|
|
113
|
-
"points",
|
|
114
|
-
"d",
|
|
115
|
-
"fill",
|
|
116
|
-
"stroke",
|
|
117
|
-
"stroke-width",
|
|
118
|
-
"font-family",
|
|
119
|
-
"font-size",
|
|
120
|
-
"text-anchor",
|
|
121
|
-
],
|
|
122
|
-
},
|
|
123
|
-
allowComments: false,
|
|
124
|
-
allowUnknownElements: false,
|
|
125
|
-
allowUnknownAttributes: false,
|
|
126
|
-
});
|
|
127
|
-
const cleanBuffer = Buffer.from(cleanSvg, "utf8");
|
|
128
|
-
// Basic sanity checks
|
|
129
|
-
if (cleanBuffer.length > 256 * 1024) {
|
|
130
|
-
throw new Error("SVG too large (max 256 KB)");
|
|
131
|
-
}
|
|
132
|
-
return Promise.resolve({
|
|
133
|
-
width: 0, // SVG is scalable, can’t guarantee pixel dimensions
|
|
134
|
-
height: 0,
|
|
135
|
-
format: "svg",
|
|
136
|
-
size: cleanBuffer.length,
|
|
137
|
-
safeBuffer: cleanBuffer,
|
|
138
|
-
});
|
|
139
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"detectFormat.d.ts","sourceRoot":"","sources":["../src/detectFormat.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,GACb,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS,CAyB7C"}
|
package/dist-cjs/detectFormat.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.detectFormat = detectFormat;
|
|
4
|
-
function detectFormat(buffer) {
|
|
5
|
-
if (buffer[0] === 0xff && buffer[1] === 0xd8) {
|
|
6
|
-
return "jpeg";
|
|
7
|
-
}
|
|
8
|
-
if (buffer[0] === 0x89 &&
|
|
9
|
-
buffer[1] === 0x50 &&
|
|
10
|
-
buffer[2] === 0x4e &&
|
|
11
|
-
buffer[3] === 0x47) {
|
|
12
|
-
return "png";
|
|
13
|
-
}
|
|
14
|
-
if (buffer.slice(0, 4).toString() === "RIFF" &&
|
|
15
|
-
buffer.slice(8, 12).toString() === "WEBP") {
|
|
16
|
-
return "webp";
|
|
17
|
-
}
|
|
18
|
-
const header = buffer.slice(0, 1000).toString("utf8").toLowerCase();
|
|
19
|
-
if (header.includes("<svg")) {
|
|
20
|
-
return "svg";
|
|
21
|
-
}
|
|
22
|
-
return undefined;
|
|
23
|
-
}
|
package/dist-cjs/index.d.ts
DELETED
package/dist-cjs/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC"}
|
package/dist-cjs/index.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./validators/index.js"), exports);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parse/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
|
package/dist-cjs/parse/index.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./parseJpeg.js"), exports);
|
|
18
|
-
__exportStar(require("./parsePng.js"), exports);
|
|
19
|
-
__exportStar(require("./parseSVG.js"), exports);
|
|
20
|
-
__exportStar(require("./parseWebp.js"), exports);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseJpeg.d.ts","sourceRoot":"","sources":["../../src/parse/parseJpeg.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAqB3E"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseJpeg = parseJpeg;
|
|
4
|
-
function parseJpeg(buffer) {
|
|
5
|
-
let offset = 2;
|
|
6
|
-
while (offset < buffer.length) {
|
|
7
|
-
if (buffer[offset] !== 0xff) {
|
|
8
|
-
throw new Error("Invalid JPEG marker");
|
|
9
|
-
}
|
|
10
|
-
const marker = buffer[offset + 1];
|
|
11
|
-
const length = buffer.readUInt16BE(offset + 2);
|
|
12
|
-
// SOF0 (baseline), SOF2 (progressive)
|
|
13
|
-
if (marker === 0xc0 || marker === 0xc2) {
|
|
14
|
-
const height = buffer.readUInt16BE(offset + 5);
|
|
15
|
-
const width = buffer.readUInt16BE(offset + 7);
|
|
16
|
-
return { width, height };
|
|
17
|
-
}
|
|
18
|
-
offset += 2 + length;
|
|
19
|
-
}
|
|
20
|
-
throw new Error("JPEG SOF marker not found");
|
|
21
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parsePng.d.ts","sourceRoot":"","sources":["../../src/parse/parsePng.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAKA"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parsePng = parsePng;
|
|
4
|
-
function parsePng(buffer) {
|
|
5
|
-
// IHDR chunk is at byte 8+8 = 16
|
|
6
|
-
const width = buffer.readUInt32BE(16);
|
|
7
|
-
const height = buffer.readUInt32BE(20);
|
|
8
|
-
return { width, height };
|
|
9
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseSVG.d.ts","sourceRoot":"","sources":["../../src/parse/parseSVG.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CA0BA"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseSvg = parseSvg;
|
|
4
|
-
function parseSvg(buffer) {
|
|
5
|
-
const text = buffer.toString("utf8");
|
|
6
|
-
const matchViewBox = /viewBox\s*=\s*"([^"]+)"/i.exec(text);
|
|
7
|
-
const matchWidth = /width\s*=\s*"(\d+)(px)?"/i.exec(text);
|
|
8
|
-
const matchHeight = /height\s*=\s*"(\d+)(px)?"/i.exec(text);
|
|
9
|
-
let width;
|
|
10
|
-
let height;
|
|
11
|
-
if (matchWidth && matchHeight) {
|
|
12
|
-
width = parseInt(matchWidth[1], 10);
|
|
13
|
-
height = parseInt(matchHeight[1], 10);
|
|
14
|
-
}
|
|
15
|
-
else if (matchViewBox) {
|
|
16
|
-
const parts = matchViewBox[1].split(/\s+/);
|
|
17
|
-
if (parts.length === 4) {
|
|
18
|
-
width = parseFloat(parts[2]);
|
|
19
|
-
height = parseFloat(parts[3]);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
if (!width || !height) {
|
|
23
|
-
throw new Error("Could not determine SVG dimensions");
|
|
24
|
-
}
|
|
25
|
-
return { width, height };
|
|
26
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"parseWebp.d.ts","sourceRoot":"","sources":["../../src/parse/parseWebp.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAeA"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseWebp = parseWebp;
|
|
4
|
-
function parseWebp(buffer) {
|
|
5
|
-
const chunkHeader = buffer.slice(12, 16).toString();
|
|
6
|
-
if (chunkHeader === "VP8X") {
|
|
7
|
-
const width = 1 + buffer.readUIntLE(24, 3);
|
|
8
|
-
const height = 1 + buffer.readUIntLE(27, 3);
|
|
9
|
-
return { width, height };
|
|
10
|
-
}
|
|
11
|
-
else if (chunkHeader === "VP8 ") {
|
|
12
|
-
// Simple lossless: parse frame header
|
|
13
|
-
const width = buffer.readUInt16LE(26) & 0x3fff;
|
|
14
|
-
const height = buffer.readUInt16LE(28) & 0x3fff;
|
|
15
|
-
return { width, height };
|
|
16
|
-
}
|
|
17
|
-
else {
|
|
18
|
-
throw new Error("Unsupported WEBP chunk type: " + chunkHeader);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export interface ImageValidationResult {
|
|
2
|
-
width: number;
|
|
3
|
-
height: number;
|
|
4
|
-
format: string;
|
|
5
|
-
size: number;
|
|
6
|
-
safeBuffer: Buffer;
|
|
7
|
-
}
|
|
8
|
-
export declare function validateAvatarImage(buffer: Buffer): Promise<ImageValidationResult>;
|
|
9
|
-
//# sourceMappingURL=avatarValidator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"avatarValidator.d.ts","sourceRoot":"","sources":["../../src/validators/avatarValidator.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,qBAAqB,CAAC,CA0DhC"}
|