diff --git a/frontend/package.json b/frontend/package.json index c14a21bf..d3350b4d 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -40,6 +40,7 @@ "@uiw/codemirror-theme-xcode": "^4.21.21", "@uiw/react-markdown-preview": "^5.0.7", "@vscode/markdown-it-katex": "^1.1.0", + "@yorkie-js/sdk": "0.6.28", "axios": "^1.6.5", "browser-image-resizer": "^2.4.1", "clipboardy": "^4.0.0", @@ -50,7 +51,9 @@ "color": "^4.2.3", "form-data": "^4.0.0", "hast-util-to-html": "^9.0.3", + "html2canvas": "^1.4.1", "incremental-dom": "^0.6.0", + "jspdf": "^3.0.3", "katex": "^0.16.9", "lib0": "^0.2.88", "lodash": "^4.17.21", @@ -61,6 +64,7 @@ "markdown-it-prism": "^2.3.0", "markdown-it-sanitizer": "^0.4.3", "markdown-it-task-checkbox": "^1.0.6", + "marked": "^16.3.0", "match-sorter": "^6.3.3", "moment": "^2.30.1", "notistack": "^3.0.1", @@ -81,8 +85,7 @@ "redux-persist": "^6.0.0", "refractor": "^4.8.1", "validator": "^13.12.0", - "vite-plugin-package-version": "^1.1.0", - "@yorkie-js/sdk": "0.6.28" + "vite-plugin-package-version": "^1.1.0" }, "devDependencies": { "@sentry/vite-plugin": "^2.20.1", diff --git a/frontend/src/hooks/useFileExport.ts b/frontend/src/hooks/useFileExport.ts index 3cc4c781..1c61bcc4 100644 --- a/frontend/src/hooks/useFileExport.ts +++ b/frontend/src/hooks/useFileExport.ts @@ -3,7 +3,9 @@ import { useCallback } from "react"; import { useSelector } from "react-redux"; import { selectDocument } from "../store/documentSlice"; import { selectEditor } from "../store/editorSlice"; -import { useExportFileMutation } from "./api/file"; +import { marked } from "marked"; +import { jsPDF } from "jspdf"; +import html2canvas from "html2canvas"; export const enum FileExtension { Markdown = "markdown", @@ -24,28 +26,91 @@ export const useFileExport = (): UseFileExportReturn => { const editorStore = useSelector(selectEditor); const documentStore = useSelector(selectDocument); - const exportFileMutation = useExportFileMutation(); - const handleExportFile = useCallback( async (exportType: string) => { try { const markdown = editorStore.doc?.getRoot().content?.toString() || ""; const documentName = documentStore.data?.title || "codepair_document"; + enqueueSnackbar(`${exportType.toUpperCase()} file export started`, { variant: "info", }); - const response = await exportFileMutation.mutateAsync({ - exportType, - content: markdown, - fileName: documentName, - }); + let blob: Blob; + let fileName: string; + + switch (exportType) { + case FileExtension.Markdown: + blob = new Blob([markdown], { type: "text/markdown" }); + fileName = `${documentName}.md`; + break; + case FileExtension.HTML: + { + const html = await marked(markdown); + blob = new Blob([html], { type: "text/html" }); + fileName = `${documentName}.html`; + } + break; + case FileExtension.PDF: + { + const html = await marked(markdown); + + const element = document.createElement("div"); + element.innerHTML = html; + element.style.width = "794px"; // A4 + element.style.padding = "40px"; + element.style.fontFamily = "Arial, sans-serif"; + element.style.fontSize = "14px"; + element.style.lineHeight = "1.6"; + element.style.color = "#000000"; + element.style.backgroundColor = "#ffffff"; + element.style.position = "absolute"; + element.style.left = "-9999px"; + element.style.top = "0"; + + document.body.appendChild(element); + + try { + const canvas = await html2canvas(element, { + scale: 2, + useCORS: true, + logging: false, + backgroundColor: "#ffffff", + }); + + const imgData = canvas.toDataURL("image/png"); + const pdf = new jsPDF({ + orientation: "portrait", + unit: "mm", + format: "a4", + }); + + const imgWidth = 210; + const pageHeight = 297; // A4 + const imgHeight = (canvas.height * imgWidth) / canvas.width; + let heightLeft = imgHeight; + let position = 0; + + pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight); + heightLeft -= pageHeight; - const contentDisposition = response.headers["content-disposition"]; - const fileNameMatch = contentDisposition?.match(/filename="?(.+)"?\s*$/i); - const fileName = fileNameMatch ? fileNameMatch[1] : `${documentName}.${exportType}`; + while (heightLeft > 0) { + position = heightLeft - imgHeight; + pdf.addPage(); + pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight); + heightLeft -= pageHeight; + } - const blob = new Blob([response.data], { type: response.headers["content-type"] }); + blob = pdf.output("blob"); + fileName = `${documentName}.pdf`; + } finally { + document.body.removeChild(element); + } + } + break; + default: + throw new Error(`Unsupported export type: ${exportType}`); + } const url = window.URL.createObjectURL(blob); const link = document.createElement("a"); @@ -66,7 +131,7 @@ export const useFileExport = (): UseFileExportReturn => { }); } }, - [editorStore, documentStore, enqueueSnackbar, exportFileMutation] + [editorStore, documentStore, enqueueSnackbar] ); const handleExportToPDF = () => handleExportFile(FileExtension.PDF); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc3dc6ce..ff89e2cf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@openapitools/openapi-generator-cli': specifier: ^2.16.3 - version: 2.16.3(@nestjs/platform-express@10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/core@10.4.15))(class-transformer@0.5.1)(class-validator@0.14.1)(encoding@0.1.13) + version: 2.16.3(@nestjs/platform-express@10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)))(class-transformer@0.5.1)(class-validator@0.14.1)(encoding@0.1.13) '@typescript-eslint/eslint-plugin': specifier: ^8.11.0 version: 8.13.0(@typescript-eslint/parser@8.13.0(eslint@9.12.0)(typescript@5.6.3))(eslint@9.12.0)(typescript@5.6.3) @@ -283,9 +283,15 @@ importers: hast-util-to-html: specifier: ^9.0.3 version: 9.0.3 + html2canvas: + specifier: ^1.4.1 + version: 1.4.1 incremental-dom: specifier: ^0.6.0 version: 0.6.0 + jspdf: + specifier: ^3.0.3 + version: 3.0.3 katex: specifier: ^0.16.9 version: 0.16.11 @@ -316,6 +322,9 @@ importers: markdown-it-task-checkbox: specifier: ^1.0.6 version: 1.0.6 + marked: + specifier: ^16.3.0 + version: 16.3.0 match-sorter: specifier: ^6.3.3 version: 6.4.0 @@ -881,6 +890,10 @@ packages: resolution: {integrity: sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + engines: {node: '>=6.9.0'} + '@babel/template@7.25.7': resolution: {integrity: sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==} engines: {node: '>=6.9.0'} @@ -3114,6 +3127,9 @@ packages: '@types/node@22.9.0': resolution: {integrity: sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==} + '@types/pako@2.0.4': + resolution: {integrity: sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==} + '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -3129,6 +3145,9 @@ packages: '@types/qs@6.9.16': resolution: {integrity: sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==} + '@types/raf@3.4.3': + resolution: {integrity: sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==} + '@types/randomcolor@0.5.9': resolution: {integrity: sha512-k58cfpkK15AKn1m+oRd9nh5BnuiowhbyvBBdAzcddtARMr3xRzP0VlFaAKovSG6N6Knx08EicjPlOMzDejerrQ==} @@ -3171,6 +3190,9 @@ packages: '@types/supertest@6.0.2': resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -3621,6 +3643,10 @@ packages: base-64@0.1.0: resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==} + base64-arraybuffer@1.0.2: + resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} + engines: {node: '>= 0.6.0'} + base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} @@ -3778,6 +3804,10 @@ packages: caniuse-lite@1.0.30001669: resolution: {integrity: sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==} + canvg@3.0.11: + resolution: {integrity: sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==} + engines: {node: '>=10.0.0'} + capture-stack-trace@1.0.2: resolution: {integrity: sha512-X/WM2UQs6VMHUtjUDnZTRI+i1crWteJySFzr9UpGoQa4WQffXVTTXuekjl7TjZRlcF2XfjgITT0HxZ9RnxeT0w==} engines: {node: '>=0.10.0'} @@ -4077,6 +4107,9 @@ packages: resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. + core-js@3.45.1: + resolution: {integrity: sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==} + core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -4151,6 +4184,9 @@ packages: css-in-js-utils@3.1.0: resolution: {integrity: sha512-fJAcud6B3rRu+KHYk+Bwf+WFL2MDCJJ1XG9x137tJQ0xYxor7XziQtuGFbWNdqrvF4Tk26O3H73nfVqXt/fW1A==} + css-line-break@2.1.0: + resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==} + css-rules@1.1.0: resolution: {integrity: sha512-7L6krLIRwAEVCaVKyCEL6PQjQXUmf8DM9bWYKutlZd0DqOe0SiKIGQOkFb59AjDBb+3If7SDp3X8UlzDAgYSow==} @@ -4349,6 +4385,9 @@ packages: domhandler@2.4.2: resolution: {integrity: sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==} + dompurify@3.2.7: + resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} + domutils@1.5.1: resolution: {integrity: sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==} @@ -4712,6 +4751,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-png@6.4.0: + resolution: {integrity: sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==} + fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} @@ -4734,6 +4776,9 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + figures@1.7.0: resolution: {integrity: sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==} engines: {node: '>=0.10.0'} @@ -5134,6 +5179,10 @@ packages: html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + html2canvas@1.4.1: + resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==} + engines: {node: '>=8.0.0'} + htmlparser2@3.10.1: resolution: {integrity: sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==} @@ -5280,6 +5329,9 @@ packages: resolution: {integrity: sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==} engines: {node: '>=18'} + iobuffer@5.4.0: + resolution: {integrity: sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==} + ip-address@9.0.5: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} @@ -5696,6 +5748,9 @@ packages: resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} engines: {node: '>=12', npm: '>=6'} + jspdf@3.0.3: + resolution: {integrity: sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ==} + jwa@1.4.1: resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} @@ -6129,6 +6184,11 @@ packages: markdown-to-txt@2.0.1: resolution: {integrity: sha512-Hsj7KTN8k1gutlLum3vosHwVZGnv8/cbYKWVkUyo/D1rzOYddbDesILebRfOsaVfjIBJank/AVOySBlHAYqfZw==} + marked@16.3.0: + resolution: {integrity: sha512-K3UxuKu6l6bmA5FUwYho8CfJBlsUWAooKtdGgMcERSpF7gcBUrCGsLH7wDaaNOzwq18JzSUDyoEb/YsrqMac3w==} + engines: {node: '>= 20'} + hasBin: true + marked@4.3.0: resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} engines: {node: '>= 12'} @@ -6716,6 +6776,9 @@ packages: resolution: {integrity: sha512-q/R5GrMek0vzgoomq6rm9OX+3PQve8sLwTirmK30YB3Cu0Bbt9OX9M/SIUnroN5BGJkzwGsFwDaRGD9EwBOlCA==} engines: {node: '>=4'} + pako@2.1.0: + resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -6830,6 +6893,9 @@ packages: pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + pick-util@1.1.5: resolution: {integrity: sha512-H0MaM8T7wpQ/azvB12ChZw7kpSFzjsgv3Z+N7fUWnL1McTGSEeroCngcK4eOPiFQq08rAyKX3hadcAB1kUqfXA==} @@ -7010,6 +7076,9 @@ packages: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} + raf@3.4.1: + resolution: {integrity: sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -7201,6 +7270,9 @@ packages: regenerator-runtime@0.11.1: resolution: {integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==} + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} @@ -7342,6 +7414,10 @@ packages: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rgbcolor@1.0.1: + resolution: {integrity: sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==} + engines: {node: '>= 0.8.15'} + rimraf@2.6.3: resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -7592,6 +7668,10 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} + stackblur-canvas@2.7.0: + resolution: {integrity: sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==} + engines: {node: '>=0.1.14'} + stackframe@0.3.1: resolution: {integrity: sha512-XmoiF4T5nuWEp2x2w92WdGjdHGY/cZa6LIbRsDRQR/Xlk4uW0PAUlH1zJYVffocwKpCdwyuypIp25xsSXEtZHw==} @@ -7757,6 +7837,10 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svg-pathdata@6.0.3: + resolution: {integrity: sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==} + engines: {node: '>=12.0.0'} + swagger-ui-dist@5.17.14: resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==} @@ -7823,6 +7907,9 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + text-segmentation@1.0.3: + resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==} + text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} @@ -8107,6 +8194,9 @@ packages: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} + utrie@1.0.2: + resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==} + uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true @@ -9261,6 +9351,8 @@ snapshots: dependencies: regenerator-runtime: 0.14.1 + '@babel/runtime@7.28.4': {} + '@babel/template@7.25.7': dependencies: '@babel/code-frame': 7.25.7 @@ -10381,7 +10473,7 @@ snapshots: lodash: 4.17.21 rxjs: 7.8.1 - '@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/platform-express@10.4.5)(encoding@0.1.13)(reflect-metadata@0.1.13)(rxjs@7.8.1)': + '@nestjs/core@10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/platform-express@10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)))(encoding@0.1.13)(reflect-metadata@0.1.13)(rxjs@7.8.1)': dependencies: '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2(encoding@0.1.13) @@ -10393,7 +10485,7 @@ snapshots: tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/core@10.4.15) + '@nestjs/platform-express': 10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)) transitivePeerDependencies: - encoding @@ -10432,10 +10524,9 @@ snapshots: '@nestjs/common': 10.4.5(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.14)(rxjs@7.8.1) passport: 0.7.0 - '@nestjs/platform-express@10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/core@10.4.15)': + '@nestjs/platform-express@10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))': dependencies: '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) - '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/platform-express@10.4.5)(encoding@0.1.13)(reflect-metadata@0.1.13)(rxjs@7.8.1) body-parser: 1.20.3 cors: 2.8.5 express: 4.21.1 @@ -10521,11 +10612,11 @@ snapshots: transitivePeerDependencies: - encoding - '@openapitools/openapi-generator-cli@2.16.3(@nestjs/platform-express@10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/core@10.4.15))(class-transformer@0.5.1)(class-validator@0.14.1)(encoding@0.1.13)': + '@openapitools/openapi-generator-cli@2.16.3(@nestjs/platform-express@10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)))(class-transformer@0.5.1)(class-validator@0.14.1)(encoding@0.1.13)': dependencies: '@nestjs/axios': 3.1.3(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(axios@1.7.9)(rxjs@7.8.1) '@nestjs/common': 10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) - '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/platform-express@10.4.5)(encoding@0.1.13)(reflect-metadata@0.1.13)(rxjs@7.8.1) + '@nestjs/core': 10.4.15(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1))(@nestjs/platform-express@10.4.5(@nestjs/common@10.4.15(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)))(encoding@0.1.13)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2(encoding@0.1.13) axios: 1.7.9 chalk: 4.1.2 @@ -11336,6 +11427,8 @@ snapshots: dependencies: undici-types: 6.19.8 + '@types/pako@2.0.4': {} + '@types/parse-json@4.0.2': {} '@types/plist@3.0.5': @@ -11350,6 +11443,9 @@ snapshots: '@types/qs@6.9.16': {} + '@types/raf@3.4.3': + optional: true + '@types/randomcolor@0.5.9': {} '@types/range-parser@1.2.7': {} @@ -11406,6 +11502,9 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.9 + '@types/trusted-types@2.0.7': + optional: true + '@types/unist@2.0.11': {} '@types/unist@3.0.3': {} @@ -11961,6 +12060,8 @@ snapshots: base-64@0.1.0: {} + base64-arraybuffer@1.0.2: {} + base64-js@1.5.1: {} base64url@3.0.1: {} @@ -12168,6 +12269,18 @@ snapshots: caniuse-lite@1.0.30001669: {} + canvg@3.0.11: + dependencies: + '@babel/runtime': 7.28.4 + '@types/raf': 3.4.3 + core-js: 3.45.1 + raf: 3.4.1 + regenerator-runtime: 0.13.11 + rgbcolor: 1.0.1 + stackblur-canvas: 2.7.0 + svg-pathdata: 6.0.3 + optional: true + capture-stack-trace@1.0.2: {} ccount@2.0.1: {} @@ -12479,6 +12592,9 @@ snapshots: core-js@2.6.12: {} + core-js@3.45.1: + optional: true + core-util-is@1.0.2: optional: true @@ -12572,6 +12688,10 @@ snapshots: dependencies: hyphenate-style-name: 1.1.0 + css-line-break@2.1.0: + dependencies: + utrie: 1.0.2 + css-rules@1.1.0: dependencies: cssom: 0.5.0 @@ -12774,6 +12894,11 @@ snapshots: dependencies: domelementtype: 1.3.1 + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + optional: true + domutils@1.5.1: dependencies: dom-serializer: 0.1.1 @@ -13271,6 +13396,12 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-png@6.4.0: + dependencies: + '@types/pako': 2.0.4 + iobuffer: 5.4.0 + pako: 2.1.0 + fast-safe-stringify@2.1.1: {} fast-shallow-equal@1.0.0: {} @@ -13293,6 +13424,8 @@ snapshots: dependencies: pend: 1.2.0 + fflate@0.8.2: {} + figures@1.7.0: dependencies: escape-string-regexp: 1.0.5 @@ -13853,6 +13986,11 @@ snapshots: html-void-elements@3.0.0: {} + html2canvas@1.4.1: + dependencies: + css-line-break: 2.1.0 + text-segmentation: 1.0.3 + htmlparser2@3.10.1: dependencies: domelementtype: 1.3.1 @@ -14059,6 +14197,8 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 6.2.0 + iobuffer@5.4.0: {} + ip-address@9.0.5: dependencies: jsbn: 1.1.0 @@ -14620,6 +14760,17 @@ snapshots: ms: 2.1.3 semver: 7.6.3 + jspdf@3.0.3: + dependencies: + '@babel/runtime': 7.28.4 + fast-png: 6.4.0 + fflate: 0.8.2 + optionalDependencies: + canvg: 3.0.11 + core-js: 3.45.1 + dompurify: 3.2.7 + html2canvas: 1.4.1 + jwa@1.4.1: dependencies: buffer-equal-constant-time: 1.0.1 @@ -14997,6 +15148,8 @@ snapshots: lodash.unescape: 4.0.1 marked: 4.3.0 + marked@16.3.0: {} + marked@4.3.0: {} match-sorter@6.4.0: @@ -15819,6 +15972,8 @@ snapshots: registry-url: 3.1.0 semver: 5.7.2 + pako@2.1.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -15925,6 +16080,9 @@ snapshots: pend@1.2.0: {} + performance-now@2.1.0: + optional: true + pick-util@1.1.5: dependencies: '@jonkemp/package-utils': 1.0.8 @@ -16099,6 +16257,11 @@ snapshots: quick-lru@5.1.1: {} + raf@3.4.1: + dependencies: + performance-now: 2.1.0 + optional: true + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -16316,6 +16479,9 @@ snapshots: regenerator-runtime@0.11.1: {} + regenerator-runtime@0.13.11: + optional: true + regenerator-runtime@0.14.1: {} registry-auth-token@3.4.0: @@ -16494,6 +16660,9 @@ snapshots: reusify@1.0.4: {} + rgbcolor@1.0.1: + optional: true + rimraf@2.6.3: dependencies: glob: 7.2.3 @@ -16770,6 +16939,9 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 + stackblur-canvas@2.7.0: + optional: true + stackframe@0.3.1: {} stackframe@1.3.4: {} @@ -16942,6 +17114,9 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + svg-pathdata@6.0.3: + optional: true + swagger-ui-dist@5.17.14: {} symbol-observable@4.0.0: {} @@ -17015,6 +17190,10 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + text-segmentation@1.0.3: + dependencies: + utrie: 1.0.2 + text-table@0.2.0: {} throat@2.0.2: {} @@ -17283,6 +17462,10 @@ snapshots: utils-merge@1.0.1: {} + utrie@1.0.2: + dependencies: + base64-arraybuffer: 1.0.2 + uuid@10.0.0: {} uuid@9.0.1: {}