smp-serverless-utils
Version:
Utilities for working with GCP Storage, file handling, and PDF/SVG conversions
173 lines (172 loc) • 6.96 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetchMimeType = exports.fetchRedirectUrl = exports.fetchHead = exports.validateRequest = exports.getDynamicStoryExporterPageURL = exports.getStoryExporterPageURL = exports.svgToPDF = exports.convertPixelToPts = exports.saveSvgToFile = exports.uploadToGCPBucket = exports.getFileName = void 0;
exports.getUniqueFileName = getUniqueFileName;
const storage_1 = require("@google-cloud/storage");
const path_1 = require("path");
const fs_1 = require("fs");
const puppeteer_1 = __importDefault(require("puppeteer"));
const getFileName = (queryObject, options) => {
let fileFormat = queryObject.format || "png";
let fileName = "";
// Helper function to sanitize filename
const sanitizeFileName = (name) => {
// Replace invalid characters with underscores
return name
.replace(/[\\/:*?"<>|]/g, '_') // Replace Windows/Unix invalid chars
.replace(/\s+/g, '_') // Replace spaces with underscore
.replace(/\t/g, '_') // Replace tabs with underscore
.replace(/[^\x20-\x7E]/g, '') // Remove non-printable characters
.trim();
};
if (queryObject.title) {
fileName = `${sanitizeFileName(queryObject.title)}_${Date.now()}.${fileFormat}`;
}
else if (queryObject.storyTitle && queryObject.index) {
fileName = `${sanitizeFileName(queryObject.storyTitle)}_${queryObject.index}.${fileFormat}`;
}
else {
fileName = `artboard_${queryObject?.artboardIndexes || 0}_simplified_${Date.now()}.${fileFormat}`;
}
return fileName;
};
exports.getFileName = getFileName;
const uploadToGCPBucket = async (bucketName, localPath, { orgId, functionName, storyId, fileName, }) => {
const storage = new storage_1.Storage();
try {
const destination = [process.env.FUNCTION_ENV || "local", functionName, orgId, storyId, Date.now(), fileName]
.filter(Boolean)
.join("/");
await storage.bucket(bucketName).upload(localPath, {
destination,
predefinedAcl: undefined,
metadata: {
contentDisposition: `attachment; filename=${fileName}`,
},
});
const publicUrl = `https://storage.googleapis.com/${bucketName}/${destination}`;
return publicUrl;
}
catch (error) {
console.error(`Error uploading file to GCP Bucket: ${error.message}`);
throw new Error(`Failed to upload file to GCP Bucket: ${error.message}`);
}
};
exports.uploadToGCPBucket = uploadToGCPBucket;
const saveSvgToFile = (svgData, tempDir, fileName) => {
const svgPath = (0, path_1.join)(tempDir, `${fileName.split(".")[0]}.svg`);
(0, fs_1.writeFileSync)(svgPath, svgData);
return svgPath;
};
exports.saveSvgToFile = saveSvgToFile;
function randomString() {
return (Math.random() + 1).toString(36).substring(7);
}
function getUniqueFileName(name) {
if (name === '' || typeof name !== "string") {
throw new Error("Invalid request: 'name' must be provided and must be a string.");
}
return `${name}_${Date.now()}_${randomString()}`;
}
const convertPixelToPts = (value) => {
const pts = value * 0.75;
return `${parseFloat(String(pts)).toFixed(3)}`;
};
exports.convertPixelToPts = convertPixelToPts;
const svgToPDF = async (svgData, tempDir, fileName, pageHeight, pageWidth, browser) => {
let browserInstance = null;
const manageBrowser = !browser;
try {
// If no browser is provided, launch one
if (manageBrowser) {
browserInstance = await puppeteer_1.default.launch();
browser = browserInstance;
}
if (!browser) {
throw new Error("Browser instance is required for PDF generation");
}
const svgPath = (0, exports.saveSvgToFile)(svgData, tempDir, fileName);
const page = await browser.newPage();
await page.goto(`file://${svgPath}`, { waitUntil: "networkidle0" });
await page.setViewport({
width: pageWidth,
height: pageHeight,
});
const pdfBuffer = await page.pdf({
pageRanges: "1",
printBackground: true,
height: (0, exports.convertPixelToPts)(pageHeight),
width: (0, exports.convertPixelToPts)(pageWidth),
scale: 1,
});
if (!pdfBuffer) {
throw new Error("Failed to generate PDF.");
}
const pdfFilePath = (0, path_1.join)(tempDir, `${fileName.split(".")[0]}.pdf`);
(0, fs_1.writeFileSync)(pdfFilePath, pdfBuffer);
await page.close();
(0, fs_1.unlinkSync)(svgPath);
return pdfFilePath;
}
catch (error) {
console.error("Error generating PDF:", error);
throw error;
}
finally {
// Close the browser if we created it
if (manageBrowser && browserInstance) {
await browserInstance.close();
}
}
};
exports.svgToPDF = svgToPDF;
const getStoryExporterPageURL = (storyId, organization, queryParams) => {
return `${process.env.BASE_URL}/render/${organization}/${storyId}?sToken=${process.env.STOKEN}&${queryParams}`;
};
exports.getStoryExporterPageURL = getStoryExporterPageURL;
const getDynamicStoryExporterPageURL = (exportedItemId, queryParams) => {
return `${process.env.BASE_URL}/dynamic-render/${exportedItemId}?sToken=${process.env.STOKEN}&${queryParams}`;
};
exports.getDynamicStoryExporterPageURL = getDynamicStoryExporterPageURL;
const validateRequest = (body) => {
if (!body || typeof body.id !== "string") {
throw new Error("Invalid request: 'id' must be provided and must be a string.");
}
return body.id;
};
exports.validateRequest = validateRequest;
const fetchHead = async (url) => {
const res = await fetch(url, { method: "HEAD" });
if (!res.ok) {
throw new Error(`Failed to fetch HEAD for URL: ${url}, Status: ${res.status}`);
}
return res.headers;
};
exports.fetchHead = fetchHead;
const fetchRedirectUrl = async (url) => {
try {
new URL(url);
const headers = await (0, exports.fetchHead)(url);
const location = headers.get("location");
if (!location) {
throw new Error(`Can't find redirect URL for: ${url}`);
}
return location;
}
catch (error) {
throw new Error(`Error in fetchRedirectUrl: ${error}`);
}
};
exports.fetchRedirectUrl = fetchRedirectUrl;
const fetchMimeType = async (url) => {
const headers = await (0, exports.fetchHead)(url);
const contentType = headers.get("content-type");
if (!contentType) {
throw new Error("Can't find MIME type");
}
return contentType.split(";")[0];
};
exports.fetchMimeType = fetchMimeType;