From 9968b9c51b7da3d4ee1e4b87581cfa48b6087ab2 Mon Sep 17 00:00:00 2001 From: vgcman16 <155417613+vgcman16@users.noreply.github.com> Date: Thu, 5 Jun 2025 17:56:30 -0500 Subject: [PATCH] feat: support uploading text and document files --- app/components/chat/BaseChat.tsx | 50 ++++--- app/components/chat/Chat.client.tsx | 29 ++++- app/components/chat/ChatBox.tsx | 17 ++- app/components/chat/FilePreview.tsx | 18 ++- app/utils/fileExtract.ts | 31 +++++ app/utils/fileUtils.ts | 19 +++ package.json | 2 + pnpm-lock.yaml | 194 ++++++++++++++++++++++++++++ 8 files changed, 335 insertions(+), 25 deletions(-) create mode 100644 app/utils/fileExtract.ts diff --git a/app/components/chat/BaseChat.tsx b/app/components/chat/BaseChat.tsx index 1d1803fd..65228eb5 100644 --- a/app/components/chat/BaseChat.tsx +++ b/app/components/chat/BaseChat.tsx @@ -26,6 +26,7 @@ import type { ModelInfo } from '~/lib/modules/llm/types'; import ProgressCompilation from './ProgressCompilation'; import type { ProgressAnnotation } from '~/types/context'; import type { ActionRunner } from '~/lib/runtime/action-runner'; +import { extractTextFromFile } from '~/utils/fileExtract'; import { SupabaseChatAlert } from '~/components/chat/SupabaseAlert'; import { expoUrlAtom } from '~/lib/stores/qrCodeStore'; import { useStore } from '@nanostores/react'; @@ -64,6 +65,8 @@ interface BaseChatProps { setUploadedFiles?: (files: File[]) => void; imageDataList?: string[]; setImageDataList?: (dataList: string[]) => void; + textDataList?: string[]; + setTextDataList?: (dataList: string[]) => void; actionAlert?: ActionAlert; clearAlert?: () => void; supabaseAlert?: SupabaseAlert; @@ -108,6 +111,8 @@ export const BaseChat = React.forwardRef( setUploadedFiles, imageDataList = [], setImageDataList, + textDataList = [], + setTextDataList, messages, actionAlert, clearAlert, @@ -284,20 +289,28 @@ export const BaseChat = React.forwardRef( const handleFileUpload = () => { const input = document.createElement('input'); input.type = 'file'; - input.accept = 'image/*'; + input.accept = + 'image/*,.pdf,.docx,.txt,.md,.js,.ts,.tsx,.html,.css,.json'; input.onchange = async (e) => { const file = (e.target as HTMLInputElement).files?.[0]; if (file) { - const reader = new FileReader(); - - reader.onload = (e) => { - const base64Image = e.target?.result as string; + if (file.type.startsWith('image/')) { + const reader = new FileReader(); + reader.onload = (ev) => { + const base64Image = ev.target?.result as string; + setUploadedFiles?.([...uploadedFiles, file]); + setImageDataList?.([...imageDataList, base64Image]); + setTextDataList?.([...textDataList, '']); + }; + reader.readAsDataURL(file); + } else { + const text = await extractTextFromFile(file); setUploadedFiles?.([...uploadedFiles, file]); - setImageDataList?.([...imageDataList, base64Image]); - }; - reader.readAsDataURL(file); + setImageDataList?.([...imageDataList, '']); + setTextDataList?.([...textDataList, text]); + } } }; @@ -312,20 +325,25 @@ export const BaseChat = React.forwardRef( } for (const item of items) { - if (item.type.startsWith('image/')) { + if (item.kind === 'file') { + const file = item.getAsFile(); + if (!file) continue; e.preventDefault(); - const file = item.getAsFile(); - - if (file) { + if (file.type.startsWith('image/')) { const reader = new FileReader(); - - reader.onload = (e) => { - const base64Image = e.target?.result as string; + reader.onload = (ev) => { + const base64Image = ev.target?.result as string; setUploadedFiles?.([...uploadedFiles, file]); setImageDataList?.([...imageDataList, base64Image]); + setTextDataList?.([...textDataList, '']); }; reader.readAsDataURL(file); + } else { + const text = await extractTextFromFile(file); + setUploadedFiles?.([...uploadedFiles, file]); + setImageDataList?.([...imageDataList, '']); + setTextDataList?.([...textDataList, text]); } break; @@ -432,6 +450,8 @@ export const BaseChat = React.forwardRef( setUploadedFiles={setUploadedFiles} imageDataList={imageDataList} setImageDataList={setImageDataList} + textDataList={textDataList} + setTextDataList={setTextDataList} textareaRef={textareaRef} input={input} handleInputChange={handleInputChange} diff --git a/app/components/chat/Chat.client.tsx b/app/components/chat/Chat.client.tsx index be5ff421..1ef9cd15 100644 --- a/app/components/chat/Chat.client.tsx +++ b/app/components/chat/Chat.client.tsx @@ -25,7 +25,8 @@ import { createSampler } from '~/utils/sampler'; import { getTemplates, selectStarterTemplate } from '~/utils/selectStarterTemplate'; import { logStore } from '~/lib/stores/logs'; import { streamingState } from '~/lib/stores/streaming'; -import { filesToArtifacts } from '~/utils/fileUtils'; +import { filesToArtifacts, uploadedFilesToArtifacts } from '~/utils/fileUtils'; +import { escapeBoltTags } from '~/utils/projectCommands'; import { supabaseConnection } from '~/lib/stores/supabase'; import { defaultDesignScheme, type DesignScheme } from '~/types/design-scheme'; import type { ElementInfo } from '~/components/workbench/Inspector'; @@ -123,6 +124,7 @@ export const ChatImpl = memo( const [chatStarted, setChatStarted] = useState(initialMessages.length > 0); const [uploadedFiles, setUploadedFiles] = useState([]); const [imageDataList, setImageDataList] = useState([]); + const [textDataList, setTextDataList] = useState([]); const [searchParams, setSearchParams] = useSearchParams(); const [fakeLoading, setFakeLoading] = useState(false); const files = useStore(workbenchStore.files); @@ -353,7 +355,7 @@ export const ChatImpl = memo( content: [ { type: 'text', - text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${finalMessageContent}`, + text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${uploadArtifact}${finalMessageContent}`, }, ...imageDataList.map((imageData) => ({ type: 'image', @@ -379,6 +381,7 @@ export const ChatImpl = memo( setUploadedFiles([]); setImageDataList([]); + setTextDataList([]); resetEnhancer(); @@ -398,7 +401,7 @@ export const ChatImpl = memo( content: [ { type: 'text', - text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${finalMessageContent}`, + text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${uploadArtifact}${finalMessageContent}`, }, ...imageDataList.map((imageData) => ({ type: 'image', @@ -414,6 +417,7 @@ export const ChatImpl = memo( setUploadedFiles([]); setImageDataList([]); + setTextDataList([]); resetEnhancer(); @@ -430,6 +434,18 @@ export const ChatImpl = memo( chatStore.setKey('aborted', false); + const uploadedMap: { [path: string]: string } = {}; + uploadedFiles.forEach((file, idx) => { + const text = textDataList[idx]; + if (text) { + uploadedMap[file.name] = escapeBoltTags(text); + } + }); + const uploadArtifact = + Object.keys(uploadedMap).length > 0 + ? uploadedFilesToArtifacts(uploadedMap, `uploaded-${Date.now()}`) + : ''; + if (modifiedFiles !== undefined) { const userUpdateArtifact = filesToArtifacts(modifiedFiles, `${Date.now()}`); append({ @@ -437,7 +453,7 @@ export const ChatImpl = memo( content: [ { type: 'text', - text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${userUpdateArtifact}${finalMessageContent}`, + text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${uploadArtifact}${userUpdateArtifact}${finalMessageContent}`, }, ...imageDataList.map((imageData) => ({ type: 'image', @@ -453,7 +469,7 @@ export const ChatImpl = memo( content: [ { type: 'text', - text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${finalMessageContent}`, + text: `[Model: ${model}]\n\n[Provider: ${provider.name}]\n\n${uploadArtifact}${finalMessageContent}`, }, ...imageDataList.map((imageData) => ({ type: 'image', @@ -468,6 +484,7 @@ export const ChatImpl = memo( setUploadedFiles([]); setImageDataList([]); + setTextDataList([]); resetEnhancer(); @@ -565,6 +582,8 @@ export const ChatImpl = memo( setUploadedFiles={setUploadedFiles} imageDataList={imageDataList} setImageDataList={setImageDataList} + textDataList={textDataList} + setTextDataList={setTextDataList} actionAlert={actionAlert} clearAlert={() => workbenchStore.clearAlert()} supabaseAlert={supabaseAlert} diff --git a/app/components/chat/ChatBox.tsx b/app/components/chat/ChatBox.tsx index 99aa8355..b632c470 100644 --- a/app/components/chat/ChatBox.tsx +++ b/app/components/chat/ChatBox.tsx @@ -10,6 +10,7 @@ import { ScreenshotStateManager } from './ScreenshotStateManager'; import { SendButton } from './SendButton.client'; import { IconButton } from '~/components/ui/IconButton'; import { toast } from 'react-toastify'; +import { extractTextFromFile } from '~/utils/fileExtract'; import { SpeechRecognitionButton } from '~/components/chat/SpeechRecognition'; import { SupabaseConnection } from './SupabaseConnection'; import { ExpoQrModal } from '~/components/workbench/ExpoQrModal'; @@ -50,6 +51,8 @@ interface ChatBoxProps { setModel?: ((model: string) => void) | undefined; setUploadedFiles?: ((files: File[]) => void) | undefined; setImageDataList?: ((dataList: string[]) => void) | undefined; + textDataList: string[]; + setTextDataList?: ((dataList: string[]) => void) | undefined; handleInputChange?: ((event: React.ChangeEvent) => void) | undefined; handleStop?: (() => void) | undefined; enhancingPrompt?: boolean | undefined; @@ -134,9 +137,11 @@ export const ChatBox: React.FC = (props) => { { props.setUploadedFiles?.(props.uploadedFiles.filter((_, i) => i !== index)); props.setImageDataList?.(props.imageDataList.filter((_, i) => i !== index)); + props.setTextDataList?.(props.textDataList.filter((_, i) => i !== index)); }} /> @@ -192,16 +197,22 @@ export const ChatBox: React.FC = (props) => { e.currentTarget.style.border = '1px solid var(--bolt-elements-borderColor)'; const files = Array.from(e.dataTransfer.files); - files.forEach((file) => { + files.forEach(async (file) => { if (file.type.startsWith('image/')) { const reader = new FileReader(); - reader.onload = (e) => { - const base64Image = e.target?.result as string; + reader.onload = (ev) => { + const base64Image = ev.target?.result as string; props.setUploadedFiles?.([...props.uploadedFiles, file]); props.setImageDataList?.([...props.imageDataList, base64Image]); + props.setTextDataList?.([...props.textDataList, '']); }; reader.readAsDataURL(file); + } else { + const text = await extractTextFromFile(file); + props.setUploadedFiles?.([...props.uploadedFiles, file]); + props.setImageDataList?.([...props.imageDataList, '']); + props.setTextDataList?.([...props.textDataList, text]); } }); }} diff --git a/app/components/chat/FilePreview.tsx b/app/components/chat/FilePreview.tsx index e1400cf8..4c279886 100644 --- a/app/components/chat/FilePreview.tsx +++ b/app/components/chat/FilePreview.tsx @@ -3,10 +3,11 @@ import React from 'react'; interface FilePreviewProps { files: File[]; imageDataList: string[]; + textDataList: string[]; onRemove: (index: number) => void; } -const FilePreview: React.FC = ({ files, imageDataList, onRemove }) => { +const FilePreview: React.FC = ({ files, imageDataList, textDataList, onRemove }) => { if (!files || files.length === 0) { return null; } @@ -15,7 +16,7 @@ const FilePreview: React.FC = ({ files, imageDataList, onRemov
{files.map((file, index) => (
- {imageDataList[index] && ( + {imageDataList[index] ? (
{file.name}
+ ) : ( +
+
+ +
+ {file.name} +
+
)}
))} diff --git a/app/utils/fileExtract.ts b/app/utils/fileExtract.ts new file mode 100644 index 00000000..c71c4706 --- /dev/null +++ b/app/utils/fileExtract.ts @@ -0,0 +1,31 @@ +import * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs'; +import pdfWorker from 'pdfjs-dist/build/pdf.worker.mjs'; +import mammoth from 'mammoth/mammoth.browser'; + +pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker; + +export async function extractTextFromFile(file: File): Promise { + if (file.type === 'application/pdf' || file.name.toLowerCase().endsWith('.pdf')) { + const arrayBuffer = await file.arrayBuffer(); + const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; + const texts: string[] = []; + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const content = await page.getTextContent(); + texts.push(content.items.map((item: any) => item.str).join(' ')); + } + return texts.join('\n'); + } + + if ( + file.type === + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || + file.name.toLowerCase().endsWith('.docx') + ) { + const arrayBuffer = await file.arrayBuffer(); + const result = await mammoth.extractRawText({ arrayBuffer }); + return result.value; + } + + return file.text(); +} diff --git a/app/utils/fileUtils.ts b/app/utils/fileUtils.ts index 2a1c8756..331e95c4 100644 --- a/app/utils/fileUtils.ts +++ b/app/utils/fileUtils.ts @@ -119,3 +119,22 @@ ${files[filePath].content} `; }; + +export const uploadedFilesToArtifacts = ( + files: { [path: string]: string }, + id: string, +): string => { + return ` + +${Object.keys(files) + .map( + (filePath) => ` + +${files[filePath]} + +`, + ) + .join('\n')} + + `; +}; diff --git a/package.json b/package.json index 8bb32cf8..a3753eb4 100644 --- a/package.json +++ b/package.json @@ -123,10 +123,12 @@ "jspdf": "^2.5.2", "jszip": "^3.10.1", "lucide-react": "^0.485.0", + "mammoth": "^1.9.1", "mime": "^4.0.4", "nanostores": "^0.10.3", "ollama-ai-provider": "^0.15.2", "path-browserify": "^1.0.1", + "pdfjs-dist": "^5.3.31", "react": "^18.3.1", "react-beautiful-dnd": "^13.1.1", "react-chartjs-2": "^5.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a1717515..ce72fa3c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -248,6 +248,9 @@ importers: lucide-react: specifier: ^0.485.0 version: 0.485.0(react@18.3.1) + mammoth: + specifier: ^1.9.1 + version: 1.9.1 mime: specifier: ^4.0.4 version: 4.0.6 @@ -260,6 +263,9 @@ importers: path-browserify: specifier: ^1.0.1 version: 1.0.1 + pdfjs-dist: + specifier: ^5.3.31 + version: 5.3.31 react: specifier: ^18.3.1 version: 18.3.1 @@ -2095,6 +2101,70 @@ packages: nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0 react: '>=18.0.0' + '@napi-rs/canvas-android-arm64@0.1.70': + resolution: {integrity: sha512-I/YOuQ0wbkVYxVaYtCgN42WKTYxNqFA0gTcTrHIGG1jfpDSyZWII/uHcjOo4nzd19io6Y4+/BqP8E5hJgf9OmQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/canvas-darwin-arm64@0.1.70': + resolution: {integrity: sha512-4pPGyXetHIHkw2TOJHujt3mkCP8LdDu8+CT15ld9Id39c752RcI0amDHSuMLMQfAjvusA9B5kKxazwjMGjEJpQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/canvas-darwin-x64@0.1.70': + resolution: {integrity: sha512-+2N6Os9LbkmDMHL+raknrUcLQhsXzc5CSXRbXws9C3pv/mjHRVszQ9dhFUUe9FjfPhCJznO6USVdwOtu7pOrzQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.70': + resolution: {integrity: sha512-QjscX9OaKq/990sVhSMj581xuqLgiaPVMjjYvWaCmAJRkNQ004QfoSMEm3FoTqM4DRoquP8jvuEXScVJsc1rqQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@napi-rs/canvas-linux-arm64-gnu@0.1.70': + resolution: {integrity: sha512-LNakMOwwqwiHIwMpnMAbFRczQMQ7TkkMyATqFCOtUJNlE6LPP/QiUj/mlFrNbUn/hctqShJ60gWEb52ZTALbVw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/canvas-linux-arm64-musl@0.1.70': + resolution: {integrity: sha512-wBTOllEYNfJCHOdZj9v8gLzZ4oY3oyPX8MSRvaxPm/s7RfEXxCyZ8OhJ5xAyicsDdbE5YBZqdmaaeP5+xKxvtg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/canvas-linux-riscv64-gnu@0.1.70': + resolution: {integrity: sha512-GVUUPC8TuuFqHip0rxHkUqArQnlzmlXmTEBuXAWdgCv85zTCFH8nOHk/YCF5yo0Z2eOm8nOi90aWs0leJ4OE5Q==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@napi-rs/canvas-linux-x64-gnu@0.1.70': + resolution: {integrity: sha512-/kvUa2lZRwGNyfznSn5t1ShWJnr/m5acSlhTV3eXECafObjl0VBuA1HJw0QrilLpb4Fe0VLywkpD1NsMoVDROQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/canvas-linux-x64-musl@0.1.70': + resolution: {integrity: sha512-aqlv8MLpycoMKRmds7JWCfVwNf1fiZxaU7JwJs9/ExjTD8lX2KjsO7CTeAj5Cl4aEuzxUWbJPUUE2Qu9cZ1vfg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/canvas-win32-x64-msvc@0.1.70': + resolution: {integrity: sha512-Q9QU3WIpwBTVHk4cPfBjGHGU4U0llQYRXgJtFtYqqGNEOKVN4OT6PQ+ve63xwIPODMpZ0HHyj/KLGc9CWc3EtQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/canvas@0.1.70': + resolution: {integrity: sha512-nD6NGa4JbNYSZYsTnLGrqe9Kn/lCkA4ybXt8sx5ojDqZjr2i0TWAHxx/vhgfjX+i3hCdKWufxYwi7CfXqtITSA==} + engines: {node: '>= 10'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -3683,6 +3753,9 @@ packages: arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -3791,6 +3864,9 @@ packages: bluebird-lst@1.0.9: resolution: {integrity: sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==} + bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + bluebird@3.7.2: resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} @@ -4407,6 +4483,9 @@ packages: diffie-hellman@5.0.3: resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + dingbat-to-unicode@1.0.1: + resolution: {integrity: sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w==} + dir-compare@4.2.0: resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} @@ -4447,6 +4526,9 @@ packages: resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} engines: {node: '>=12'} + duck@0.1.12: + resolution: {integrity: sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg==} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -5644,6 +5726,9 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lop@0.4.2: + resolution: {integrity: sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw==} + loupe@3.1.3: resolution: {integrity: sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==} @@ -5684,6 +5769,11 @@ packages: resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + mammoth@1.9.1: + resolution: {integrity: sha512-4S2v1eP4Yo4so0zGNicJKcP93su3wDPcUk+xvkjSG75nlNjSkDJu8BhWQ+e54BROM0HfA6nPzJn12S6bq2Ko6w==} + engines: {node: '>=12.0.0'} + hasBin: true + markdown-extensions@1.1.1: resolution: {integrity: sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q==} engines: {node: '>=0.10.0'} @@ -6336,6 +6426,9 @@ packages: oniguruma-to-es@2.3.0: resolution: {integrity: sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g==} + option@0.2.4: + resolution: {integrity: sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -6445,6 +6538,10 @@ packages: resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} engines: {node: '>=0.12'} + pdfjs-dist@5.3.31: + resolution: {integrity: sha512-EhPdIjNX0fcdwYQO+e3BAAJPXt+XI29TZWC7COhIXs/K0JHcUt1Gdz1ITpebTwVMFiLsukdUZ3u0oTO7jij+VA==} + engines: {node: '>=20.16.0 || >=22.3.0'} + pe-library@0.4.1: resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} engines: {node: '>=12', npm: '>=6'} @@ -7375,6 +7472,9 @@ packages: spdx-license-ids@3.0.21: resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} @@ -7717,6 +7817,9 @@ packages: unconfig@0.5.5: resolution: {integrity: sha512-VQZ5PT9HDX+qag0XdgQi8tJepPhXiR/yVOkn707gJDKo31lGjRilPREiQJ9Z6zd/Ugpv6ZvO5VxVIcatldYcNQ==} + underscore@1.13.7: + resolution: {integrity: sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==} + undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} @@ -8179,6 +8282,10 @@ packages: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} + xmlbuilder@10.1.1: + resolution: {integrity: sha512-OyzrcFLL/nb6fMGHbiRDuPup9ljBycsdCypwuyg5AAHvyWzGfChJpCXMG88AGTIMFhGZ9RccFN1e6lhg3hkwKg==} + engines: {node: '>=4.0'} + xmlbuilder@15.1.1: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} @@ -9967,6 +10074,50 @@ snapshots: nanostores: 0.10.3 react: 18.3.1 + '@napi-rs/canvas-android-arm64@0.1.70': + optional: true + + '@napi-rs/canvas-darwin-arm64@0.1.70': + optional: true + + '@napi-rs/canvas-darwin-x64@0.1.70': + optional: true + + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.70': + optional: true + + '@napi-rs/canvas-linux-arm64-gnu@0.1.70': + optional: true + + '@napi-rs/canvas-linux-arm64-musl@0.1.70': + optional: true + + '@napi-rs/canvas-linux-riscv64-gnu@0.1.70': + optional: true + + '@napi-rs/canvas-linux-x64-gnu@0.1.70': + optional: true + + '@napi-rs/canvas-linux-x64-musl@0.1.70': + optional: true + + '@napi-rs/canvas-win32-x64-msvc@0.1.70': + optional: true + + '@napi-rs/canvas@0.1.70': + optionalDependencies: + '@napi-rs/canvas-android-arm64': 0.1.70 + '@napi-rs/canvas-darwin-arm64': 0.1.70 + '@napi-rs/canvas-darwin-x64': 0.1.70 + '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.70 + '@napi-rs/canvas-linux-arm64-gnu': 0.1.70 + '@napi-rs/canvas-linux-arm64-musl': 0.1.70 + '@napi-rs/canvas-linux-riscv64-gnu': 0.1.70 + '@napi-rs/canvas-linux-x64-gnu': 0.1.70 + '@napi-rs/canvas-linux-x64-musl': 0.1.70 + '@napi-rs/canvas-win32-x64-msvc': 0.1.70 + optional: true + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -11967,6 +12118,10 @@ snapshots: arg@5.0.2: {} + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + argparse@2.0.1: {} aria-hidden@1.2.4: @@ -12063,6 +12218,8 @@ snapshots: dependencies: bluebird: 3.7.2 + bluebird@3.4.7: {} + bluebird@3.7.2: {} bn.js@4.12.1: {} @@ -12748,6 +12905,8 @@ snapshots: miller-rabin: 4.0.1 randombytes: 2.1.0 + dingbat-to-unicode@1.0.1: {} + dir-compare@4.2.0: dependencies: minimatch: 3.1.2 @@ -12805,6 +12964,10 @@ snapshots: dotenv@16.4.7: {} + duck@0.1.12: + dependencies: + underscore: 1.13.7 + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -14338,6 +14501,12 @@ snapshots: dependencies: js-tokens: 4.0.0 + lop@0.4.2: + dependencies: + duck: 0.1.12 + option: 0.2.4 + underscore: 1.13.7 + loupe@3.1.3: {} lowercase-keys@2.0.0: {} @@ -14390,6 +14559,19 @@ snapshots: - bluebird - supports-color + mammoth@1.9.1: + dependencies: + '@xmldom/xmldom': 0.8.10 + argparse: 1.0.10 + base64-js: 1.5.1 + bluebird: 3.4.7 + dingbat-to-unicode: 1.0.1 + jszip: 3.10.1 + lop: 0.4.2 + path-is-absolute: 1.0.1 + underscore: 1.13.7 + xmlbuilder: 10.1.1 + markdown-extensions@1.1.1: {} markdown-table@3.0.4: {} @@ -15466,6 +15648,8 @@ snapshots: regex: 5.1.1 regex-recursion: 5.1.1 + option@0.2.4: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -15581,6 +15765,10 @@ snapshots: safe-buffer: 5.2.1 sha.js: 2.4.11 + pdfjs-dist@5.3.31: + optionalDependencies: + '@napi-rs/canvas': 0.1.70 + pe-library@0.4.1: {} peek-stream@1.1.3: @@ -16584,6 +16772,8 @@ snapshots: spdx-license-ids@3.0.21: {} + sprintf-js@1.0.3: {} + sprintf-js@1.1.3: {} ssri@10.0.6: @@ -16910,6 +17100,8 @@ snapshots: transitivePeerDependencies: - supports-color + underscore@1.13.7: {} + undici-types@6.19.8: {} undici-types@6.20.0: {} @@ -17439,6 +17631,8 @@ snapshots: xml-name-validator@5.0.0: {} + xmlbuilder@10.1.1: {} + xmlbuilder@15.1.1: {} xmlchars@2.2.0: {}