commit 671297320ec6ff93d05ad150836dd0a2b291c83c Author: abdullahalam123 Date: Sun Oct 12 11:55:45 2025 +0530 feat: add initial project setup with core PDF tools and utilities - Implement core PDF manipulation tools (split, merge, convert, etc.) - Add state management and UI utilities - Set up build configuration with Vite and TailwindCSS - Include essential dependencies for PDF processing - Add gitignore and basic project configuration files diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d600b6c --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + diff --git a/about.html b/about.html new file mode 100644 index 0000000..7c6d04f --- /dev/null +++ b/about.html @@ -0,0 +1,202 @@ + + + + + + + About Bentopdf - Fast, Private, and Free PDF Tools + + + + + + + + + + + + + +
+ +
+

+ We believe PDF tools should be fast, private, and free. +

+

+ No compromises. +

+
+ +
+ +
+
+ +

Our Mission

+

+ To provide the most comprehensive PDF toolbox that respects your privacy and never asks for payment. + We believe essential document tools should be accessible to everyone, everywhere, without barriers. +

+
+
+ +
+
+
+ Our Core Philosophy +

Privacy First. Always.

+

+ In an era where data is a commodity, we take a different approach. All processing for Bentopdf + tools happens locally in your browser. This means your files never touch our servers, we never + see your documents, and we don't track what you do. Your documents remain completely and + unequivocally private. It's not just a feature; it's our foundation. +

+
+
+
+
+
+
+ +
+
+
+
+ +
+

+ Why Bentopdf? +

+
+
+ +
+

Built for Speed

+

No waiting for uploads or downloads to a server. By processing + files directly in your browser using modern web technologies like WebAssembly, we offer + unparalleled speed for all our tools.

+
+
+
+ +
+

Completely Free

+

No trials, no subscriptions, no hidden fees, and no "premium" + features held hostage. We believe powerful PDF tools should be a public utility, not a + profit center.

+
+
+
+ +
+

No Account Required

+

Start using any tool immediately. We don't need your email, a + password, or any personal information. Your workflow should be frictionless and anonymous. +

+
+
+
+ +
+

Open Source Spirit

+

Built with transparency in mind. We leverage incredible + open-source libraries like PDF-lib and PDF.js, and believe in the community-driven effort to + make powerful tools accessible to everyone.

+
+
+
+
+ +
+ +
+

Ready to get started?

+

+ Join thousands of users who trust Bentopdf for their daily document needs. Experience the difference + that privacy and performance can make. +

+ + Explore All Tools + +
+ +
+ + + + + + + \ No newline at end of file diff --git a/contact.html b/contact.html new file mode 100644 index 0000000..9861dea --- /dev/null +++ b/contact.html @@ -0,0 +1,108 @@ + + + + + + + Contact Us - BentoPDF + + + + + + + + +
+
+

Get in Touch

+

+ We'd love to hear from you. Whether you have a question, feedback, or a feature request, please don't + hesitate to reach out. +

+
+ +
+

+ You can reach us directly by email at: + contact@bentopdf.com +

+
+ +
+ + + + + + + \ No newline at end of file diff --git a/faq.html b/faq.html new file mode 100644 index 0000000..cebfece --- /dev/null +++ b/faq.html @@ -0,0 +1,229 @@ + + + + + + + Frequently Asked Questions - BentoPDF + + + + + + + + + + + + + +
+ +
+

+ Frequently Asked Questions +

+

+ Have questions? We've got answers. Here are some of the most common things people ask about BentoPDF. +

+
+ +
+
+ +

Are my files safe and private?

+ +
+
+

Absolutely. This is the most important feature of BentoPDF. All processing + happens 100% locally in your web browser. Your files are never uploaded to any server, which + means we—or anyone else—can never see them. Your privacy is guaranteed.

+
+
+ +
+ +

Is BentoPDF really free? What's the catch?

+ +
+
+

Yes, it's completely free, and there's no catch. There are no hidden fees, no subscription plans, + no usage limits, and no premium-only features. We believe essential tools should be accessible + to everyone.

+
+
+ +
+ +

Do I need an internet connection to use the tools?

+ +
+
+

After you load the website for the first time, most tools will work completely offline! Because + all the processing libraries are loaded into your browser, you can disconnect from the internet + and continue to merge, split, compress, and edit your PDFs securely. Some niche tools that + require external data (like Markdown to PDF with web images) may need a connection.

+
+
+ +
+ +

Are there any file size or usage limitations?

+ +
+
+

No, we do not impose any artificial limits on file size, the number of files, or how many times + you can use a tool. The only practical limitation is the processing power and memory of your own + computer, as very large or complex files may take longer to process.

+
+
+ +
+ +

Why did my PDF fail to process?

+ +
+
+

Failures are rare but can happen for a few reasons:

+
    +
  • The PDF might be corrupted or not compliant with standard specifications.
  • +
  • The file could be encrypted with a password you don't have. Please use our Decrypt tool + first.
  • +
  • The file might be a special "XFA" or dynamic form-based PDF, which some of our tools cannot + process.
  • +
+
+
+ +
+ +

Do you track my activity on BentoPDF?

+ +
+
+

We care about your privacy. BentoPDF does not track personal information. We use Simple Analytics solely to see anonymous visit counts. This + means we can know how many users visit our site, but we never know who you are. + Simple Analytics is fully GDPR-compliant and respects your privacy.

+
+
+ +
+ +

What technology does BentoPDF use?

+ +
+
+

BentoPDF is built on the power of modern web technologies. We primarily use JavaScript libraries + like PDF-lib.js and PDFKit.js that are compiled to run + efficiently in your browser via WebAssembly. This allows for powerful, server-like processing + without your data ever leaving your machine.

+
+
+
+ +
+ +
+

Still have questions?

+

+ If you can't find the answer you're looking for, feel free to reach out to our support team. We're + always Bento to help. +

+ + Contact Us + +
+ +
+ + + + + + + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..e315b40 --- /dev/null +++ b/index.html @@ -0,0 +1,579 @@ + + + + + + + BentoPDF - The Privacy First PDF Toolkit + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+

+ The + PDF Toolkit + built for privacy. +

+

+ Fast, Secure and Forever Free. +

+
+ No Signups + Unlimited Use + Works Offline +
+ + Start + Using - Forever Free + +
+ +
+ +
+

+ Why BentoPDF? +

+
+
+
+ +

No Signup

+
+

Start instantly, no accounts or emails.

+
+
+
+ +

No Uploads

+
+

100% client-side, your files never leave your device.

+
+
+
+ +

Forever Free

+
+

All tools, no trials, no paywalls.

+
+
+
+ +

No Limits

+
+

Use as much as you want, no hidden caps.

+
+
+
+ +

Batch Processing

+
+

Handle unlimited PDFs in one go.

+
+
+
+ +

Lightning Fast

+
+

Process PDFs instantly, without waiting or delays.

+
+
+
+ +
+ +
+

+ Get Started with Tools +

+

Click a tool to open the file uploader

+
+ +
+
+
+ + + + +
+
+ +
+
+
+ + + + + + + + + + + +
+ + +
+
+

+ Your data never leaves your device + + + We keep + + + + your information safe + + by following global security standards. +

+
+
+ + All the processing happens locally on your device. + +
+ +
+ +
+
+ GDPR compliance +
+

GDPR compliance

+

Protects the personal data + and privacy of individuals within the European Union.

+
+ +
+
+ CCPA compliance +
+

CCPA compliance

+

Gives California residents + rights over how their personal information is collected, used, and shared.

+
+ +
+
+ HIPAA compliance +
+

HIPAA compliance

+

Sets safeguards for handling + sensitive health information in the United States healthcare system.

+
+ +
+
+ + + +
+ +
+

+ Frequently Asked Questions +

+ +
+ +
+

+ Yes, absolutely. All tools on BentoPDF are 100% free to use, with no file limits, no sign-ups, + and no + watermarks. We believe everyone deserves access to simple, powerful PDF tools without a paywall. +

+
+
+ +
+ +
+

+ Your files are as secure as possible because they **never leave your computer**. All processing + happens + directly in your web browser (client-side). We never upload your files to a server, so you + maintain + complete privacy and control over your documents. +

+
+
+ +
+ +
+

+ Yes! Since BentoPDF runs entirely in your browser, it works on any operating system with a + modern web + browser, including Windows, macOS, Linux, iOS, and Android. +

+
+
+ + +
+ +
+

+ Yes. BentoPDF is fully GDPR compliant. Since all file processing happens locally in your browser + and we + never collect or transmit your files to any server, we have no access to your data. This ensures + you are + always in control of your documents. +

+
+
+ + +
+ +
+

+ No. We never store, track, or log your files. Everything you do on BentoPDF happens in your + browser + memory and disappears once you close the page. There are no uploads, no history logs, and no + servers + involved. +

+
+
+ + +
+ +
+

+ Most PDF tools upload your files to a server for processing. BentoPDF never does that. We use + secure, + modern web technology to process your files directly in your browser. This means faster + performance, + stronger privacy, and complete peace of mind. +

+
+
+ + +
+ +
+

+ By running entirely inside your browser, BentoPDF ensures that your files never leave your + device. This + eliminates the risks of server hacks, data breaches, or unauthorized access. Your files remain + yours—always. +

+
+
+ + +
+ +
+

+ We care about your privacy. BentoPDF does not track personal information. We use Simple Analytics solely to see anonymous visit counts. This + means we can know how many users visit our site, but we never know who you are. + Simple Analytics is fully GDPR-compliant and respects your privacy. +

+
+
+
+ + +
+ +
+

+ What Our Users Say +

+
+
+
+
+

Sarah L.

+
★★★★★
+
+
+

"This is the tool I've been searching for! It's fast, free, and I love that + my confidential documents never get uploaded to some random server. A lifesaver for my freelance + work."

+
+
+
+
+

Mark Chen

+
★★★★★
+
+
+

"Finally, a PDF editor that just works. No ads, no sign-ups, no nonsense. + The merge tool is surprisingly powerful. I've already bookmarked it on all my devices."

+
+
+
+
+

Anonymous User A-35Z

+
★☆☆☆☆
+
+
+

"Terrible. It won't let me upload my files to the cloud. How is my Big Data + Tech Overlord supposed to know I signed a permission slip for my kid's field trip? Useless for + my data profile."

+
+
+
+
+

Dr. Brickson

+
★★★★★
+
+
+

"As a researcher, data privacy is paramount. BentoPDF's client-side + processing model is exactly what my institution recommends. It's robust, reliable, and secure. A + fantastic resource."

+
+
+
+
+

AdTracker Pro

+
★☆☆☆☆
+
+
+

"This website is broken. My ad blocker says it hasn't blocked a single + tracker. How am I supposed to know if a product is good if it's not following me around the + internet for a week? 1 star."

+
+
+
+
+

Raj P.

+
★★★★★
+
+
+

"Simple, elegant, and powerful. I needed to merge 50 reports, and it + handled it instantly without crashing my browser. This is what a web tool should be. Highly + recommended."

+
+
+
+ +
+
+
+

+ Like My Work? +

+

+ BentoPDF is a passion project, built to provide a free, private, and powerful PDF toolkit for + everyone. If you find it useful, consider supporting its development. Every coffee helps! +

+ + + + Buy Me a Coffee + + +
+
+ + + +
+ + + + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..242b3c5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,11141 @@ +{ + "name": "bento-pdf", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bento-pdf", + "version": "0.0.0", + "dependencies": { + "@tailwindcss/vite": "^4.1.14", + "blob-stream": "^0.1.3", + "cropperjs": "^1.6.1", + "heic2any": "^0.0.4", + "html2canvas": "^1.4.1", + "javascript-obfuscator": "^4.1.1", + "jspdf": "^3.0.3", + "jszip": "^3.10.1", + "lucide": "^0.545.0", + "pdf-lib": "^1.17.1", + "pdfjs-dist": "^5.4.296", + "pdfkit": "^0.17.2", + "sortablejs": "^1.15.6", + "tailwindcss": "^4.1.14", + "terser": "^5.44.0", + "tesseract.js": "^6.0.1", + "tiff": "^7.1.2", + "utif": "^3.1.0" + }, + "devDependencies": { + "@types/blob-stream": "^0.1.33", + "@types/html2canvas": "^0.5.35", + "@types/pdfkit": "^0.17.3", + "@types/sortablejs": "^1.15.8", + "@types/utif": "^3.0.6", + "ts-migrate": "^0.1.35", + "typescript": "~5.9.3", + "vite": "^7.1.7", + "vite-plugin-node-polyfills": "^0.24.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", + "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", + "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz", + "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", + "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.4.tgz", + "integrity": "sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", + "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.28.3", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", + "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", + "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", + "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-flow": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", + "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/traverse": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", + "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", + "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.3.tgz", + "integrity": "sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.28.0", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.28.0", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-classes": "^7.28.3", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.28.0", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-explicit-resource-management": "^7.28.0", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.28.0", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.7", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.28.3", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "core-js-compat": "^3.43.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-flow": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.27.1.tgz", + "integrity": "sha512-ez3a2it5Fn6P54W8QkbfIyyIbxlXvcxyWHHvno1Wg0Ej5eiJY5hBb8ExttoIOJJk7V2dZE6prP7iby5q2aQ0Lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-transform-flow-strip-types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", + "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/register": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.28.3.tgz", + "integrity": "sha512-CieDOtd8u208eI49bYl4z1J22ySFw87IGwE+IswFEExH7e3rLgKb0WNQeumnacQ1+VoDJLYI5QFA3AJZuyZQfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "find-cache-dir": "^2.0.0", + "make-dir": "^2.1.0", + "pirates": "^4.0.6", + "source-map-support": "^0.5.16" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@javascript-obfuscator/escodegen": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@javascript-obfuscator/escodegen/-/escodegen-2.3.0.tgz", + "integrity": "sha512-QVXwMIKqYMl3KwtTirYIA6gOCiJ0ZDtptXqAv/8KWLG9uQU2fZqTVy7a/A5RvcoZhbDoFfveTxuGxJ5ibzQtkw==", + "license": "BSD-2-Clause", + "dependencies": { + "@javascript-obfuscator/estraverse": "^5.3.0", + "esprima": "^4.0.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/@javascript-obfuscator/estraverse": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@javascript-obfuscator/estraverse/-/estraverse-5.4.0.tgz", + "integrity": "sha512-CZFX7UZVN9VopGbjTx4UXaXsi9ewoM1buL0kY7j1ftYdSs7p2spv9opxFjHlQ/QGTgh4UqufYqJJ0WKLml7b6w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.80.tgz", + "integrity": "sha512-DxuT1ClnIPts1kQx8FBmkk4BQDTfI5kIzywAaMjQSXfNnra5UFU9PwurXrl+Je3bJ6BGsp/zmshVVFbCmyI+ww==", + "license": "MIT", + "optional": true, + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.80", + "@napi-rs/canvas-darwin-arm64": "0.1.80", + "@napi-rs/canvas-darwin-x64": "0.1.80", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.80", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.80", + "@napi-rs/canvas-linux-arm64-musl": "0.1.80", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-gnu": "0.1.80", + "@napi-rs/canvas-linux-x64-musl": "0.1.80", + "@napi-rs/canvas-win32-x64-msvc": "0.1.80" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.80.tgz", + "integrity": "sha512-sk7xhN/MoXeuExlggf91pNziBxLPVUqF2CAVnB57KLG/pz7+U5TKG8eXdc3pm0d7Od0WreB6ZKLj37sX9muGOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.80.tgz", + "integrity": "sha512-O64APRTXRUiAz0P8gErkfEr3lipLJgM6pjATwavZ22ebhjYl/SUbpgM0xcWPQBNMP1n29afAC/Us5PX1vg+JNQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.80.tgz", + "integrity": "sha512-FqqSU7qFce0Cp3pwnTjVkKjjOtxMqRe6lmINxpIZYaZNnVI0H5FtsaraZJ36SiTHNjZlUB69/HhxNDT1Aaa9vA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.80.tgz", + "integrity": "sha512-eyWz0ddBDQc7/JbAtY4OtZ5SpK8tR4JsCYEZjCE3dI8pqoWUC8oMwYSBGCYfsx2w47cQgQCgMVRVTFiiO38hHQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.80.tgz", + "integrity": "sha512-qwA63t8A86bnxhuA/GwOkK3jvb+XTQaTiVML0vAWoHyoZYTjNs7BzoOONDgTnNtr8/yHrq64XXzUoLqDzU+Uuw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.80.tgz", + "integrity": "sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.80.tgz", + "integrity": "sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.80.tgz", + "integrity": "sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.80.tgz", + "integrity": "sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.80", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.80.tgz", + "integrity": "sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pdf-lib/standard-fonts": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz", + "integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==", + "license": "MIT", + "dependencies": { + "pako": "^1.0.6" + } + }, + "node_modules/@pdf-lib/upng": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz", + "integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==", + "license": "MIT", + "dependencies": { + "pako": "^1.0.10" + } + }, + "node_modules/@rollup/plugin-inject": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", + "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", + "integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz", + "integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz", + "integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz", + "integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz", + "integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz", + "integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz", + "integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz", + "integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz", + "integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz", + "integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz", + "integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz", + "integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz", + "integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz", + "integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz", + "integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz", + "integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz", + "integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz", + "integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz", + "integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz", + "integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz", + "integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz", + "integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/helpers/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz", + "integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.6.0", + "lightningcss": "1.30.1", + "magic-string": "^0.30.19", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz", + "integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.5.1" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-arm64": "4.1.14", + "@tailwindcss/oxide-darwin-x64": "4.1.14", + "@tailwindcss/oxide-freebsd-x64": "4.1.14", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.14", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.14", + "@tailwindcss/oxide-linux-x64-musl": "4.1.14", + "@tailwindcss/oxide-wasm32-wasi": "4.1.14", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.14", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.14" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz", + "integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz", + "integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz", + "integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz", + "integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz", + "integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz", + "integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz", + "integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz", + "integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz", + "integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz", + "integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.5.0", + "@emnapi/runtime": "^1.5.0", + "@emnapi/wasi-threads": "^1.1.0", + "@napi-rs/wasm-runtime": "^1.0.5", + "@tybys/wasm-util": "^0.10.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz", + "integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz", + "integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.14.tgz", + "integrity": "sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.14", + "@tailwindcss/oxide": "4.1.14", + "tailwindcss": "4.1.14" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@ts-morph/bootstrap": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@ts-morph/bootstrap/-/bootstrap-0.16.0.tgz", + "integrity": "sha512-FYW3bK5EBeAgpHu0qZ57gHbLjzgzC81y5EJmrebzIhXSYg6OgZu5lFHpF5NJ7CwM7ZMhxX1PG+DRA8e+skopKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/common": "~0.16.0" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.16.0.tgz", + "integrity": "sha512-SgJpzkTgZKLKqQniCjLaE3c2L2sdL7UShvmTmPBejAKd2OKV/yfMpQ2IWpAuA+VY5wy7PkSUaEObIqEK6afFuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.2.11", + "minimatch": "^5.1.0", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@ts-morph/common/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@ts-morph/common/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/blob-stream": { + "version": "0.1.33", + "resolved": "https://registry.npmjs.org/@types/blob-stream/-/blob-stream-0.1.33.tgz", + "integrity": "sha512-HNHZ1S6W7F8PhxdyAastunpUC8cAZim78UIfqbL79gLzylp8EZep68yxAh11hTRoEvsqHAg/MECgmKF8+V0HzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/html2canvas": { + "version": "0.5.35", + "resolved": "https://registry.npmjs.org/@types/html2canvas/-/html2canvas-0.5.35.tgz", + "integrity": "sha512-1A2dtWZbOIZ+rUK8jmAx1We/EiNV+5vScpphU3AF14Vby6COIazi/9StosrvlVCqlQegRhsEgZf7QYOuWbwuuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jquery": "*" + } + }, + "node_modules/@types/jquery": { + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.33.tgz", + "integrity": "sha512-SeyVJXlCZpEki5F0ghuYe+L+PprQta6nRZqhONt9F13dWBtR/ftoaIbdRQ7cis7womE+X2LKhsDdDtkkDhJS6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sizzle": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.7.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz", + "integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.14.0" + } + }, + "node_modules/@types/pako": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz", + "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==", + "license": "MIT" + }, + "node_modules/@types/pdfkit": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/pdfkit/-/pdfkit-0.17.3.tgz", + "integrity": "sha512-E4tp2qFaghqfS4K5TR4Gn1uTIkg0UAkhUgvVIszr5cS6ZmbioPWEkvhNDy3GtR9qdKC8DLQAnaaMlTcf346VsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.10.tgz", + "integrity": "sha512-TC0dmN0K8YcWEAEfiPi5gJP14eJe30TTGjkvek3iM/1NdHHsdCA/Td6GvNndMOo/iSnIsZ4HuuhrYPDAmbxzww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sortablejs": { + "version": "1.15.8", + "resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.8.tgz", + "integrity": "sha512-b79830lW+RZfwaztgs1aVPgbasJ8e7AXtZYHTELNXZPsERt4ymJdjV4OccDbHQAvHrCcFpbF78jkm0R6h/pZVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/utif": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/utif/-/utif-3.0.6.tgz", + "integrity": "sha512-4XHDJkLHoUeLA2P/VOd6dpDJpSTpV84tN9EyHojZrW22jtUR0VrdLwVRUAw+oI3g72vSzOo+YQOzfwcW6WYHLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/validator": { + "version": "13.15.3", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.15.3.tgz", + "integrity": "sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==", + "license": "MIT" + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.0.0.tgz", + "integrity": "sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==", + "license": "MIT", + "dependencies": { + "es6-object-assign": "^1.1.0", + "is-nan": "^1.2.1", + "object-is": "^1.0.1", + "util": "^0.12.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.7.tgz", + "integrity": "sha512-2mP3TwtkY/aTv5X3ZsMpNAbOnyoC/aMJwJSoaELPkHId0nSQgFcnU4dRW3isxiz7+zBexk0ym3WNVjMiQBnJSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.14.tgz", + "integrity": "sha512-GM9c0cWWR8Ga7//Ves/9KRgTS8nLausCkP3CGiFLrnwA2CDUluXgaQqvrULoR2Ujrd/mz/lkX87F5BHFsNr5sQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/blob": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", + "integrity": "sha512-YRc9zvVz4wNaxcXmiSgb9LAg7YYwqQ2xd0Sj6osfA7k/PKmIGVlnOYs3wOFdkRC9/JpQu8sGt/zHgJV7xzerfg==" + }, + "node_modules/blob-stream": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/blob-stream/-/blob-stream-0.1.3.tgz", + "integrity": "sha512-xXwyhgVmPsFVFFvtM5P0syI17/oae+MIjLn5jGhuD86mmSJ61EWMWmbPrV/0+bdcH9jQ2CzIhmTQKNUJL7IPog==", + "license": "MIT", + "dependencies": { + "blob": "0.0.4" + } + }, + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==", + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/brotli": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz", + "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.1.2" + } + }, + "node_modules/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.17.0" + } + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-rsa/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/browserify-sign": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "dev": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001749", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz", + "integrity": "sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/canvg": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.11.tgz", + "integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chance": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/chance/-/chance-1.1.9.tgz", + "integrity": "sha512-TfxnA/DcZXRTA4OekA2zL9GH8qscbbl6X0ZqU4tXhGveVY/mXWvEQLt5GwZcYXTEyEFflVtj+pG8nc8EwSm1RQ==", + "license": "MIT" + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cipher-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/class-validator": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz", + "integrity": "sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==", + "license": "MIT", + "dependencies": { + "@types/validator": "^13.11.8", + "libphonenumber-js": "^1.10.53", + "validator": "^13.9.0" + } + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js": { + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz", + "integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", + "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-jest-runner": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/create-jest-runner/-/create-jest-runner-0.5.3.tgz", + "integrity": "sha512-a9VY2doMBmzRollJB3Ft3/Y5fBceSWJ4gdyVsg4/d7nP1S4715VG939s2VnITDj79YBmRgKhjGjNRv1c+Kre1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.2", + "jest-worker": "^24.0.0", + "throat": "^4.1.0" + }, + "bin": { + "create-jest-runner": "generator/index.js" + } + }, + "node_modules/create-jest-runner/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-jest-runner/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-jest-runner/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/create-jest-runner/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-jest-runner/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/create-jest-runner/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/create-jest-runner/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cropperjs": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/cropperjs/-/cropperjs-1.6.1.tgz", + "integrity": "sha512-F4wsi+XkDHCOMrHMYjrTEE4QBOrsHHN5/2VsVAaRq8P7E5z7xQpT75S+f/9WikmBEailas3+yo+6zPIomW+NOA==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dfa": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz", + "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==", + "license": "MIT" + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/domain-browser": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", + "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/dompurify": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optional": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.233", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.233.tgz", + "integrity": "sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==", + "dev": true, + "license": "ISC" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-brackets/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/fast-glob/node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/fast-glob/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/fast-glob/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "license": "MIT" + }, + "node_modules/fast-png": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz", + "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==", + "license": "MIT", + "dependencies": { + "@types/pako": "^2.0.3", + "iobuffer": "^5.3.2", + "pako": "^2.1.0" + } + }, + "node_modules/fast-png/node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "license": "MIT" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/flow-parser": { + "version": "0.287.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.287.0.tgz", + "integrity": "sha512-92XfPmSg6zV/UD/R3Hw+sxBUi3SiIL8COqD7p3HRZysX1ksrw5MdPhpqox0U0Hd5lqQ9F1AJCi92fnRO7WDgFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fontkit": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-2.0.4.tgz", + "integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==", + "license": "MIT", + "dependencies": { + "@swc/helpers": "^0.5.12", + "brotli": "^1.3.2", + "clone": "^2.1.2", + "dfa": "^1.2.0", + "fast-deep-equal": "^3.1.3", + "restructure": "^3.0.0", + "tiny-inflate": "^1.0.3", + "unicode-properties": "^1.4.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/heic2any": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/heic2any/-/heic2any-0.0.4.tgz", + "integrity": "sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA==", + "license": "MIT" + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/idb-keyval": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", + "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", + "license": "Apache-2.0" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inversify": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/inversify/-/inversify-6.0.1.tgz", + "integrity": "sha512-B3ex30927698TJENHR++8FfEaJGqoWOgI6ZY5Ht/nLUsFCwHn6akbwtnUAPCgUepAnTpe2qHxhDNjoKLyz6rgQ==", + "license": "MIT" + }, + "node_modules/iobuffer": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz", + "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==", + "license": "MIT" + }, + "node_modules/is-accessor-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz", + "integrity": "sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz", + "integrity": "sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.3.tgz", + "integrity": "sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-url": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", + "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "license": "MIT" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-timers-promises": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", + "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/javascript-obfuscator": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/javascript-obfuscator/-/javascript-obfuscator-4.1.1.tgz", + "integrity": "sha512-gt+KZpIIrrxXHEQGD8xZrL8mTRwRY0U76/xz/YX0gZdPrSqQhT/c7dYLASlLlecT3r+FxE7je/+C0oLnTDCx4A==", + "hasInstallScript": true, + "license": "BSD-2-Clause", + "dependencies": { + "@javascript-obfuscator/escodegen": "2.3.0", + "@javascript-obfuscator/estraverse": "5.4.0", + "acorn": "8.8.2", + "assert": "2.0.0", + "chalk": "4.1.2", + "chance": "1.1.9", + "class-validator": "0.14.1", + "commander": "10.0.0", + "eslint-scope": "7.1.1", + "eslint-visitor-keys": "3.3.0", + "fast-deep-equal": "3.1.3", + "inversify": "6.0.1", + "js-string-escape": "1.0.1", + "md5": "2.3.0", + "mkdirp": "2.1.3", + "multimatch": "5.0.0", + "opencollective-postinstall": "2.0.3", + "process": "0.11.10", + "reflect-metadata": "0.1.13", + "source-map-support": "0.5.21", + "string-template": "1.0.0", + "stringz": "2.1.0", + "tslib": "2.5.0" + }, + "bin": { + "javascript-obfuscator": "bin/javascript-obfuscator" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/javascript-obfuscator" + } + }, + "node_modules/javascript-obfuscator/node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/javascript-obfuscator/node_modules/commander": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.0.tgz", + "integrity": "sha512-zS5PnTI22FIRM6ylNW8G4Ap0IEOyk62fhLSD0+uHRT9McRCLGpkVNvao4bjimpK/GShynyQkFFxHhwMcETmduA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/javascript-obfuscator/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "license": "0BSD" + }, + "node_modules/jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jiti": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jpeg-exif": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/jpeg-exif/-/jpeg-exif-1.1.4.tgz", + "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==", + "license": "MIT" + }, + "node_modules/js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jscodeshift": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.6.4.tgz", + "integrity": "sha512-+NF/tlNbc2WEhXUuc4WEJLsJumF84tnaMUZW2hyJw3jThKKRvsPX4sPJVgO1lPE28z0gNL+gwniLG9d8mYvQCQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.1.6", + "@babel/parser": "^7.1.6", + "@babel/plugin-proposal-class-properties": "^7.1.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/preset-env": "^7.1.6", + "@babel/preset-flow": "^7.0.0", + "@babel/preset-typescript": "^7.1.0", + "@babel/register": "^7.0.0", + "babel-core": "^7.0.0-bridge.0", + "colors": "^1.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.16.1", + "temp": "^0.8.1", + "write-file-atomic": "^2.3.0" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5-writer": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/json5-writer/-/json5-writer-0.1.8.tgz", + "integrity": "sha512-h5sqkk/vSKvESOUTBniGWs8p8nTzHsoDrxPS9enJfQVINqXv3lm+FAyizLwbrCwCn0q7NXqDBb+r8AdUdK3XZw==", + "dev": true, + "license": "ISC", + "dependencies": { + "jscodeshift": "^0.6.3" + } + }, + "node_modules/jspdf": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.3.tgz", + "integrity": "sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.26.9", + "fast-png": "^6.2.0", + "fflate": "^0.8.1" + }, + "optionalDependencies": { + "canvg": "^3.0.11", + "core-js": "^3.6.0", + "dompurify": "^3.2.4", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libphonenumber-js": { + "version": "1.12.23", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.12.23.tgz", + "integrity": "sha512-RN3q3gImZ91BvRDYjWp7ICz3gRn81mW5L4SW+2afzNCC0I/nkXstBgZThQGTE3S/9q5J90FH4dP+TXx8NhdZKg==", + "license": "MIT" + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/linebreak": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz", + "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==", + "license": "MIT", + "dependencies": { + "base64-js": "0.0.8", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/linebreak/node_modules/base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-3.4.0.tgz", + "integrity": "sha512-ILKe88NeMt4gmDvk/eb615U/IVn7K9KWGkoYbdatQ69Z65nj1ZzjM6fHXfcs0Uge+e+EGnMW7DY4T9yko8vWFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^3.2.0", + "cli-cursor": "^2.1.0", + "wrap-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lru-cache/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/lucide": { + "version": "0.545.0", + "resolved": "https://registry.npmjs.org/lucide/-/lucide-0.545.0.tgz", + "integrity": "sha512-mrBH0upkb1TH8ZLkf0XERQAKMdTJ1C+Offr7eSvanmdQ7JrV8jkrFw5jgRAS8fygiZgG4X9mfEg/BXCL+mNMRw==", + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.19", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", + "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.3.tgz", + "integrity": "sha512-sjAkg21peAG9HS+Dkx7hlG9Ztx7HLeKnvB3NQRcu/mltCVmvkF0pisbiTSfDVYTT86XEfZrTUosLdZLStquZUw==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "license": "MIT", + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.10.5" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-stdlib-browser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz", + "integrity": "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert": "^2.0.0", + "browser-resolve": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "create-require": "^1.1.1", + "crypto-browserify": "^3.12.1", + "domain-browser": "4.22.0", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "isomorphic-timers-promises": "^1.0.1", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "pkg-dir": "^5.0.0", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.1", + "url": "^0.11.4", + "util": "^0.12.4", + "vm-browserify": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-stdlib-browser/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/node-stdlib-browser/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/node-stdlib-browser/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/node-stdlib-browser/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/node-stdlib-browser/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/node-stdlib-browser/node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-stdlib-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-stdlib-browser/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/opencollective-postinstall": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", + "license": "MIT", + "bin": { + "opencollective-postinstall": "index.js" + } + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "license": "MIT", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-asn1/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/pbkdf2": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pbkdf2/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/pdf-lib": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz", + "integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==", + "license": "MIT", + "dependencies": { + "@pdf-lib/standard-fonts": "^1.0.0", + "@pdf-lib/upng": "^1.0.1", + "pako": "^1.0.11", + "tslib": "^1.11.1" + } + }, + "node_modules/pdfjs-dist": { + "version": "5.4.296", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz", + "integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=20.16.0 || >=22.3.0" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.80" + } + }, + "node_modules/pdfkit": { + "version": "0.17.2", + "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.17.2.tgz", + "integrity": "sha512-UnwF5fXy08f0dnp4jchFYAROKMNTaPqb/xgR8GtCzIcqoTnbOqtp3bwKvO4688oHI6vzEEs8Q6vqqEnC5IUELw==", + "license": "MIT", + "dependencies": { + "crypto-js": "^4.2.0", + "fontkit": "^2.0.4", + "jpeg-exif": "^1.1.4", + "linebreak": "^1.1.0", + "png-js": "^1.0.0" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "license": "MIT", + "optional": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/png-js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz", + "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g==" + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "license": "MIT", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/recast": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.16.2.tgz", + "integrity": "sha512-O/7qXi51DPjRVdbrpNzoBQH5dnAPQNbfoOFyRiUwreTMJfIHYOEBzwuH+c0+/BTSJ3CQyKs6ILSWXhESH6Op3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "0.11.7", + "esprima": "~4.0.0", + "private": "~0.1.5", + "source-map": "~0.6.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "license": "Apache-2.0" + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", + "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/repeat-element": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true, + "license": "MIT" + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/restructure": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/restructure/-/restructure-3.0.2.tgz", + "integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==", + "license": "MIT" + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "license": "MIT OR SEE LICENSE IN FEEL-FREE.md", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.52.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", + "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.4", + "@rollup/rollup-android-arm64": "4.52.4", + "@rollup/rollup-darwin-arm64": "4.52.4", + "@rollup/rollup-darwin-x64": "4.52.4", + "@rollup/rollup-freebsd-arm64": "4.52.4", + "@rollup/rollup-freebsd-x64": "4.52.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.4", + "@rollup/rollup-linux-arm-musleabihf": "4.52.4", + "@rollup/rollup-linux-arm64-gnu": "4.52.4", + "@rollup/rollup-linux-arm64-musl": "4.52.4", + "@rollup/rollup-linux-loong64-gnu": "4.52.4", + "@rollup/rollup-linux-ppc64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-gnu": "4.52.4", + "@rollup/rollup-linux-riscv64-musl": "4.52.4", + "@rollup/rollup-linux-s390x-gnu": "4.52.4", + "@rollup/rollup-linux-x64-gnu": "4.52.4", + "@rollup/rollup-linux-x64-musl": "4.52.4", + "@rollup/rollup-openharmony-arm64": "4.52.4", + "@rollup/rollup-win32-arm64-msvc": "4.52.4", + "@rollup/rollup-win32-ia32-msvc": "4.52.4", + "@rollup/rollup-win32-x64-gnu": "4.52.4", + "@rollup/rollup-win32-x64-msvc": "4.52.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/sha.js/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/snapdragon/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sortablejs": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.6.tgz", + "integrity": "sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==", + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "license": "MIT", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "deprecated": "See https://github.com/lydell/source-map-url#deprecated", + "dev": true, + "license": "MIT" + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stackblur-canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz", + "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-template": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-1.0.0.tgz", + "integrity": "sha512-SLqR3GBUXuoPP5MmYtD7ompvXiG87QjT6lzOszyXjTM86Uu7At7vNnt2xgyTLq5o9T4IxTYFyGxcULqpsmsfdg==", + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringz": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/stringz/-/stringz-2.1.0.tgz", + "integrity": "sha512-KlywLT+MZ+v0IRepfMxRtnSvDCMc3nR1qqCs3m/qIbSOWkNZYT8XHQA31rS3TnKp0c5xjZu3M4GY/2aRKSi/6A==", + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwindcss": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", + "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.1.tgz", + "integrity": "sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/temp": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.4.tgz", + "integrity": "sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser": { + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tesseract.js": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-6.0.1.tgz", + "integrity": "sha512-/sPvMvrCtgxnNRCjbTYbr7BRu0yfWDsMZQ2a/T5aN/L1t8wUQN6tTWv6p6FwzpoEBA0jrN2UD2SX4QQFRdoDbA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "bmp-js": "^0.1.0", + "idb-keyval": "^6.2.0", + "is-url": "^1.2.4", + "node-fetch": "^2.6.9", + "opencollective-postinstall": "^2.0.3", + "regenerator-runtime": "^0.13.3", + "tesseract.js-core": "^6.0.0", + "wasm-feature-detect": "^1.2.11", + "zlibjs": "^0.3.1" + } + }, + "node_modules/tesseract.js-core": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-6.0.0.tgz", + "integrity": "sha512-1Qncm/9oKM7xgrQXZXNB+NRh19qiXGhxlrR8EwFbK5SaUbPZnS5OMtP/ghtqfd23hsr1ZvZbZjeuAGcMxd/ooA==", + "license": "Apache-2.0" + }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha512-wCVxLDcFxw7ujDxaeJC6nfl2XfHJNYs8yUYJnvMgtPEFlttP9tHSfRUv2vBe6C4hkVFPWoP1P6ZccbYjmSEkKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tiff": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/tiff/-/tiff-7.1.2.tgz", + "integrity": "sha512-E5rXZJJc3Il0eR4u30PLE6R8DOx/IFyjgS1JhyYvKSEVAAHLTXVwGgZRmLE//K8Pt8d+y4M0Xae30wNGb9Qmxg==", + "license": "MIT", + "dependencies": { + "iobuffer": "^6.0.0", + "pako": "^2.1.0" + } + }, + "node_modules/tiff/node_modules/iobuffer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-6.0.1.tgz", + "integrity": "sha512-SZWYkWNfjIXIBYSDpXDYIgshqtbOPsi4lviawAEceR1Kqk+sHDlcQjWrzNQsii80AyBY0q5c8HCTNjqo74ul+Q==", + "license": "MIT" + }, + "node_modules/tiff/node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-buffer/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-migrate": { + "version": "0.1.35", + "resolved": "https://registry.npmjs.org/ts-migrate/-/ts-migrate-0.1.35.tgz", + "integrity": "sha512-EmXahqwIP0a6fE1BLKKVMgJEeYn9V+CxJ19qFJ/DzkPL4PjDI/FcgPo8D519amBPy2nnlc/x1V6R6aIeHdD87w==", + "dev": true, + "license": "MIT", + "dependencies": { + "create-jest-runner": "^0.5.3", + "json5": "^2.1.1", + "json5-writer": "^0.1.8", + "ts-migrate-plugins": "^0.1.35", + "ts-migrate-server": "^0.1.33", + "updatable-log": "^0.2.0", + "yargs": "^15.0.2" + }, + "bin": { + "ts-migrate": "build/cli.js", + "ts-migrate-full": "bin/ts-migrate-full.sh" + }, + "peerDependencies": { + "typescript": ">4.0" + } + }, + "node_modules/ts-migrate-plugins": { + "version": "0.1.35", + "resolved": "https://registry.npmjs.org/ts-migrate-plugins/-/ts-migrate-plugins-0.1.35.tgz", + "integrity": "sha512-DUkx7ClKhxKYPWDha9DJTZ6LhwEUszL90uH5I/O11K/6TbA96ytln1O3HL6Pt83i4mAKOlg0mQ6AMsPtL5FFkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint": "^7.14.0", + "jscodeshift": "^0.13.0", + "json-schema": "^0.4.0", + "ts-migrate-server": "^0.1.33" + }, + "peerDependencies": { + "typescript": ">4.0" + } + }, + "node_modules/ts-migrate-plugins/node_modules/ast-types": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz", + "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ts-migrate-plugins/node_modules/jscodeshift": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.13.1.tgz", + "integrity": "sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.13.16", + "@babel/parser": "^7.13.16", + "@babel/plugin-proposal-class-properties": "^7.13.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", + "@babel/plugin-proposal-optional-chaining": "^7.13.12", + "@babel/plugin-transform-modules-commonjs": "^7.13.8", + "@babel/preset-flow": "^7.13.13", + "@babel/preset-typescript": "^7.13.0", + "@babel/register": "^7.13.16", + "babel-core": "^7.0.0-bridge.0", + "chalk": "^4.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.2.4", + "micromatch": "^3.1.10", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.20.4", + "temp": "^0.8.4", + "write-file-atomic": "^2.3.0" + }, + "bin": { + "jscodeshift": "bin/jscodeshift.js" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "node_modules/ts-migrate-plugins/node_modules/recast": { + "version": "0.20.5", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.20.5.tgz", + "integrity": "sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ast-types": "0.14.2", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ts-migrate-plugins/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/ts-migrate-server": { + "version": "0.1.33", + "resolved": "https://registry.npmjs.org/ts-migrate-server/-/ts-migrate-server-0.1.33.tgz", + "integrity": "sha512-MYHy10yzL2fkb2FHFQ9f54gqc5KkaVthTjtpwS4bTroYCONDelp1hbz5nxKWaP3q2oc3kBVeGuAR91RNI+yK+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ts-morph/bootstrap": "^0.16.0", + "pretty-ms": "^7.0.1", + "updatable-log": "^0.2.0" + }, + "peerDependencies": { + "typescript": ">4.0" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz", + "integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-properties": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz", + "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==", + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.0", + "unicode-trie": "^2.0.0" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "license": "MIT", + "dependencies": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + }, + "node_modules/unicode-trie/node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "license": "MIT" + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/union-value/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/updatable-log": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/updatable-log/-/updatable-log-0.2.0.tgz", + "integrity": "sha512-gR48/mTR6YFB+B1sNoap3nx8HFbEvDl0ej9KhlQTFZdmP8yL5fzFiCUfeHCUf1QvNnXowY1pM9iiGkPKrd0XyQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "chalk": "^2.4.2", + "figures": "^3.0.0", + "log-update": "^3.3.0" + } + }, + "node_modules/updatable-log/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/updatable-log/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/updatable-log/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/updatable-log/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/updatable-log/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/updatable-log/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/updatable-log/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true, + "license": "MIT" + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/utif": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/utif/-/utif-3.1.0.tgz", + "integrity": "sha512-WEo4D/xOvFW53K5f5QTaTbbiORcm2/pCL9P6qmJnup+17eYfKaEhDeX9PeQkuyEoIxlbGklDuGl8xwuXYMrrXQ==", + "license": "MIT", + "dependencies": { + "pako": "^1.0.5" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true, + "license": "MIT" + }, + "node_modules/validator": { + "version": "13.15.15", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.15.tgz", + "integrity": "sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vite": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz", + "integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-node-polyfills": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.24.0.tgz", + "integrity": "sha512-GA9QKLH+vIM8NPaGA+o2t8PDfFUl32J8rUp1zQfMKVJQiNkOX4unE51tR6ppl6iKw5yOrDAdSH7r/UIFLCVhLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rollup/plugin-inject": "^5.0.5", + "node-stdlib-browser": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/davidmyersdev" + }, + "peerDependencies": { + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/wasm-feature-detect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz", + "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==", + "license": "Apache-2.0" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zlibjs": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz", + "integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==", + "license": "MIT", + "engines": { + "node": "*" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..6ed7ccc --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "bento-pdf", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "obfuscate": "node scripts/build.mjs" + }, + "devDependencies": { + "@types/blob-stream": "^0.1.33", + "@types/html2canvas": "^0.5.35", + "@types/pdfkit": "^0.17.3", + "@types/sortablejs": "^1.15.8", + "@types/utif": "^3.0.6", + "ts-migrate": "^0.1.35", + "typescript": "~5.9.3", + "vite": "^7.1.7", + "vite-plugin-node-polyfills": "^0.24.0" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.14", + "blob-stream": "^0.1.3", + "cropperjs": "^1.6.1", + "heic2any": "^0.0.4", + "html2canvas": "^1.4.1", + "javascript-obfuscator": "^4.1.1", + "jspdf": "^3.0.3", + "jszip": "^3.10.1", + "lucide": "^0.545.0", + "pdf-lib": "^1.17.1", + "pdfjs-dist": "^5.4.296", + "pdfkit": "^0.17.2", + "sortablejs": "^1.15.6", + "tailwindcss": "^4.1.14", + "terser": "^5.44.0", + "tesseract.js": "^6.0.1", + "tiff": "^7.1.2", + "utif": "^3.1.0" + } +} diff --git a/privacy.html b/privacy.html new file mode 100644 index 0000000..29813db --- /dev/null +++ b/privacy.html @@ -0,0 +1,187 @@ + + + + + + + Privacy Policy - BentoPDF + + + + + + + + + + + +
+
+

Privacy Policy

+

Last Updated: September 14, 2025

+ + +
+
+ + + + + + \ No newline at end of file diff --git a/public/images/favicon.svg b/public/images/favicon.svg new file mode 100644 index 0000000..81cc658 --- /dev/null +++ b/public/images/favicon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..13851c3 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,56 @@ +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +const sourceDir = path.join(__dirname, '../unoptimized-js'); +const outputDir = path.join(__dirname, '../dist/js'); + +if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); +} + +function processFile(filePath) { + const relativePath = path.relative(sourceDir, filePath); + const outputPath = path.join(outputDir, relativePath); + const outputDirForFile = path.dirname(outputPath); + + // Create subdirectories in the output folder + if (!fs.existsSync(outputDirForFile)) { + fs.mkdirSync(outputDirForFile, { recursive: true }); + } + + try { + // 1. Obfuscate the file + console.log(`Obfuscating: ${filePath}`); + const obfuscateCmd = `npx javascript-obfuscator "${filePath}" --output "${outputPath}"`; + execSync(obfuscateCmd); + + // 2. Minify the obfuscated file using Terser + console.log(`Minifying: ${outputPath}`); + const minifyCmd = `npx terser "${outputPath}" -o "${outputPath}" --compress --mangle`; + execSync(minifyCmd); + + console.log(`Success: ${outputPath}`); + } catch (error) { + console.error(`Error processing file ${filePath}:`, error.message); + } +} + +function processDirectory(dirPath) { + fs.readdirSync(dirPath).forEach(file => { + const filePath = path.join(dirPath, file); + const stats = fs.statSync(filePath); + + if (stats.isDirectory()) { + processDirectory(filePath); + } else if (path.extname(filePath) === '.js') { + if (filePath !== path.join(__dirname, 'build.js')) { + processFile(filePath); + } + } + }); +} + +console.log('Starting JavaScript build process...'); +processDirectory(sourceDir); +console.log('Build complete. Files are in the /dist/js folder.'); \ No newline at end of file diff --git a/src/css/styles.css b/src/css/styles.css new file mode 100644 index 0000000..07f362e --- /dev/null +++ b/src/css/styles.css @@ -0,0 +1,358 @@ +@import "tailwindcss"; + +html { + scroll-behavior: smooth; +} + +body { + font-family: 'DM Sans', sans-serif; + background-color: #111827; + /* bg-gray-900 */ + color: #d1d5db; + /* text-gray-300 */ +} + +.tool-card { + transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out; + border: 1px solid #374151; + /* border-gray-700 */ +} + +.tool-card:hover { + transform: translateY(-5px); + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2), 0 4px 6px -2px rgba(0, 0, 0, 0.1); + border-color: #4f46e5; + /* indigo-600 */ +} + +.btn { + transition: background-color 0.2s ease-in-out, transform 0.1s ease-in-out; +} + +.btn:active { + transform: scale(0.98); +} + +/* Custom file input */ +input[type="file"]::file-selector-button { + @apply bg-indigo-600 text-white font-semibold py-2 px-4 rounded-lg cursor-pointer hover:bg-indigo-700 transition-colors duration-200 mr-4; +} + +/* Custom scrollbar */ +::-webkit-scrollbar { + width: 8px; +} + +::-webkit-scrollbar-track { + background: #1f2937; + /* bg-gray-800 */ +} + +::-webkit-scrollbar-thumb { + background: #4f46e5; + /* indigo-600 */ + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: #4338ca; + /* indigo-700 */ +} + +/* Style for drag-and-drop placeholder */ +.sortable-ghost { + opacity: 0.4; + border: 2px dashed #4f46e5; +} + +#embed-pdf-container>div { + width: 100%; + height: 100%; +} + +#tool-interface { + color: #39A0ED; +} + +.page-thumbnail, +#file-list > li { + cursor: grab; +} + +.sortable-chosen { + cursor: grabbing; +} + +.compare-viewer-wrapper.overlay-mode { + position: relative; + width: 100%; + height: 75vh; + overflow: auto; + border: 2px solid #374151; + border-radius: 0.5rem; + background-color: #1f2937; +} + +/* This rule now ONLY applies to canvases in overlay mode */ +.compare-viewer-wrapper.overlay-mode canvas { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: auto; +} + +.compare-viewer-wrapper.side-by-side-mode { + display: flex; + gap: 1rem; + width: 100%; +} + +.pdf-panel { + flex: 1; + min-width: 0; + overflow: auto; + height: 75vh; + border: 2px solid #374151; + border-radius: 0.5rem; + background-color: #1f2937; +} + +/* This rule ensures canvases in side-by-side panels display at their natural rendered size. */ +.pdf-panel canvas { + display: block; + margin: 0 auto; +} + +footer a { + transition: color 0.2s ease-in-out; +} + +.marker { + position: relative; + display: inline-block; +} + +.marker::after { + content: ''; + position: absolute; + bottom: -5px; + left: 0; + width: 100%; + /* height: 30px; */ + background-color: orange; /* Yellow marker color */ + z-index: -1; + transform: skew(-20deg); +} + +.pill { + background-color: #374151; /* bg-gray-700 */ + color: #d1d5db; /* text-gray-300 */ + padding: 8px 16px; + border-radius: 9999px; /* rounded-full */ + font-size: 14px; + font-weight: 500; +} + +.cta-button { + background-color: #4f46e5; /* indigo-600 */ + color: white; + font-weight: 600; + padding: 12px 24px; + border-radius: 8px; /* rounded-lg */ + transition: background-color 0.2s ease-in-out; +} + +.cta-button:hover { + background-color: #4338ca; /* indigo-700 */ +} +.marker-text { + background-color: rgba(255, 255, 0, 0.5); /* Yellow marker color */ + padding: 0 5px; +} +.feature-card { + background-color: #1f2937; /* bg-gray-800 */ + padding: 24px; + border-radius: 8px; /* rounded-lg */ + text-align: center; +} + +.nav-link { + @apply text-gray-300 hover:bg-gray-700 hover:text-white px-3 py-2 rounded-md text-sm font-medium transition-colors; +} + +.mobile-nav-link { + @apply text-gray-300 hover:bg-gray-700 hover:text-white block px-3 py-2 rounded-md text-base font-medium transition-colors; +} + +.marker-slanted { + position: relative; + display: inline-block; +} + +.marker-slanted::before { + content: ""; + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 6px; + background: linear-gradient(120deg, #6366f1, #8b5cf6); + z-index: -1; +} + +.section-divider { + height: 1px; + background: linear-gradient(to right, transparent, #4f46e5, transparent); /* Fades from transparent to indigo and back */ + margin: 2rem auto; /* my-16 */ + max-width: 42rem; /* max-w-xl */ + opacity: 0.5; +} + +.btn-gradient { + display: inline-block; + padding: 0.75rem 2rem; /* py-3 px-8 */ + border-radius: 0.5rem; /* rounded-lg */ + background-image: linear-gradient(to bottom, #6366f1, #4f46e5); /* from-indigo-500 to-indigo-600 */ + color: #ffffff; /* text-white */ + font-weight: 600; /* font-semibold */ + transition-property: all; + transition-duration: 200ms; + transform: translateY(0); +} + +.btn-gradient:hover { + box-shadow: 0 10px 15px -3px rgba(79, 70, 229, 0.3), 0 4px 6px -4px rgba(79, 70, 229, 0.3); /* hover:shadow-xl hover:shadow-indigo-500/30 */ + transform: translateY(-0.25rem); /* hover:-translate-y-1 */ +} + +.btn-gradient:focus { + outline: 2px solid transparent; + outline-offset: 2px; + box-shadow: 0 0 0 2px #111827, 0 0 0 4px #818cf8; /* focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-900 focus:ring-indigo-400 */ +} + +.btn-gradient:disabled { + opacity: 0.5; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + +.solid-spinner { + width: 64px; /* w-16 */ + height: 64px; /* h-16 */ + border: 5px solid #374151; /* border-gray-700 */ + border-bottom-color: #4f46e5; /* border-indigo-600 */ + border-radius: 50%; + display: inline-block; + box-sizing: border-box; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +#signature-ghost { + position: absolute; + z-index: 100; + pointer-events: none; /* Allows clicks to pass through to the canvas */ + opacity: 0.6; + background-size: contain; + background-repeat: no-repeat; +} + +/* Highlight for selected signature in the saved list */ +.saved-signature.selected { + border-color: #4f46e5; /* indigo-600 */ + box-shadow: 0 0 10px rgba(79, 70, 229, 0.5); +} + +/* Cursor change when hovering over a placed signature */ +#canvas-sign.movable { + cursor: move; +} + +#canvas-sign.resize-ns { cursor: ns-resize; } +#canvas-sign.resize-ew { cursor: ew-resize; } +#canvas-sign.resize-nesw { cursor: nesw-resize; } +#canvas-sign.resize-nwse { cursor: nwse-resize; } + +.faq-item.open .faq-question { + color: #818cf8; /* indigo-400 */ +} + +.faq-item.open .faq-icon { + transform: rotate(180deg); +} + +/* Testimonial Card Styles */ +.testimonial-card { + background-color: #1f2937; /* bg-gray-800 */ + padding: 24px; + border-radius: 0.75rem; /* rounded-xl */ + border: 1px solid #374151; /* border-gray-700 */ + display: flex; + flex-direction: column; +} + +/* Find the existing .pill rule: */ +.pill { + background-color: #374151; /* bg-gray-700 */ + color: #d1d5db; /* text-gray-300 */ + padding: 8px 16px; + border-radius: 9999px; /* rounded-full */ + font-size: 14px; + font-weight: 500; +} + +/* And REPLACE it with this: */ +.pill { + background-color: #374151; /* bg-gray-700 */ + color: #d1d5db; /* text-gray-300 */ + /* Smaller padding and font size by default for mobile */ + padding: 6px 12px; + font-size: 12px; + border-radius: 9999px; /* rounded-full */ + font-weight: 500; +} + +/* On small screens (640px) and up, revert to the larger size */ +@media (min-width: 640px) { + .pill { + padding: 8px 16px; + font-size: 14px; + } +} + +/* Ensure form-field-group contents don't overflow on small screens */ +.form-field-group .capitalize { + word-break: break-all; +} + +@media (max-width: 1023px) { + #form-fields-container { + overflow-x: auto; + white-space: nowrap; + } + .form-field-group { + display: inline-block; + width: 90%; /* Adjust as needed */ + margin-right: 1rem; + } +} + + + +#page-merge-preview { + display: grid; + gap: 1rem; + padding: 1rem; + grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); +} \ No newline at end of file diff --git a/src/js/canvasEditor.ts b/src/js/canvasEditor.ts new file mode 100644 index 0000000..be5c868 --- /dev/null +++ b/src/js/canvasEditor.ts @@ -0,0 +1,273 @@ +import { showLoader, hideLoader, showAlert } from './ui.js'; +import { state } from './state.js'; +import { toolLogic } from './logic/index.js'; +import { icons, createIcons } from "lucide"; + +const editorState = { + pdf: null, + canvas: null, + context: null, + container: null, + currentPageNum: 1, + pageRendering: false, + pageNumPending: null, + scale: 1.0, + pageSnapshot: null, + isDrawing: false, + startX: 0, + startY: 0, + cropBoxes: {}, + lastInteractionRect: null, // Used to store the rectangle from the last move event +}; + +/** + * Calculates the best scale to fit the page within the container. + * @param {PDFPageProxy} page - The PDF.js page object. + */ +function calculateFitScale(page: any) { + const containerWidth = editorState.container.clientWidth; + const viewport = page.getViewport({ scale: 1.0 }); + return containerWidth / viewport.width; +} + +/** + * Renders a specific page of the PDF onto the canvas. + * @param {number} num The page number to render. + */ +async function renderPage(num: any) { + editorState.pageRendering = true; + showLoader(`Loading page ${num}...`); + + try { + const page = await editorState.pdf.getPage(num); + + // @ts-expect-error TS(2367) FIXME: This condition will always return 'false' since th... Remove this comment to see the full error message + if (editorState.scale === 'fit') { + editorState.scale = calculateFitScale(page); + } + + const viewport = page.getViewport({ scale: editorState.scale }); + editorState.canvas.height = viewport.height; + editorState.canvas.width = viewport.width; + + const renderContext = { + canvasContext: editorState.context, + viewport: viewport + }; + + await page.render(renderContext).promise; + + editorState.pageSnapshot = editorState.context.getImageData(0, 0, editorState.canvas.width, editorState.canvas.height); + redrawShapes(); + + } catch (error) { + console.error("Error rendering page:", error); + showAlert('Render Error', 'Could not display the page.'); + } finally { + editorState.pageRendering = false; + hideLoader(); + + document.getElementById('current-page-display').textContent = num; + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + document.getElementById('prev-page').disabled = num <= 1; + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + document.getElementById('next-page').disabled = num >= editorState.pdf.numPages; + + if (editorState.pageNumPending !== null) { + const pendingPage = editorState.pageNumPending; + editorState.pageNumPending = null; + queueRenderPage(pendingPage); + } + } +} + +function queueRenderPage(num: any) { + if (editorState.pageRendering) { + editorState.pageNumPending = num; + } else { + editorState.currentPageNum = num; + renderPage(num); + } +} + +function redrawShapes() { + if (editorState.pageSnapshot) { + editorState.context.putImageData(editorState.pageSnapshot, 0, 0); + } + + const currentCropBox = editorState.cropBoxes[editorState.currentPageNum - 1]; + if (currentCropBox) { + editorState.context.strokeStyle = 'rgba(79, 70, 229, 0.9)'; + editorState.context.lineWidth = 2; + editorState.context.setLineDash([8, 4]); + editorState.context.strokeRect(currentCropBox.x, currentCropBox.y, currentCropBox.width, currentCropBox.height); + editorState.context.setLineDash([]); + } +} + +function getEventCoordinates(e: any) { + const rect = editorState.canvas.getBoundingClientRect(); + const touch = e.touches ? e.touches[0] : e; + const scaleX = editorState.canvas.width / rect.width; + const scaleY = editorState.canvas.height / rect.height; + return { + x: (touch.clientX - rect.left) * scaleX, + y: (touch.clientY - rect.top) * scaleY, + }; +} + +function handleInteractionStart(e: any) { + e.preventDefault(); + const coords = getEventCoordinates(e); + editorState.isDrawing = true; + editorState.startX = coords.x; + editorState.startY = coords.y; +} + +function handleInteractionMove(e: any) { + if (!editorState.isDrawing) return; + e.preventDefault(); + + redrawShapes(); + const coords = getEventCoordinates(e); + + const x = Math.min(editorState.startX, coords.x); + const y = Math.min(editorState.startY, coords.y); + const width = Math.abs(editorState.startX - coords.x); + const height = Math.abs(editorState.startY - coords.y); + + editorState.context.strokeStyle = 'rgba(79, 70, 229, 0.9)'; + editorState.context.lineWidth = 2; + editorState.context.setLineDash([8, 4]); + editorState.context.strokeRect(x, y, width, height); + editorState.context.setLineDash([]); + + // Store the last valid rectangle drawn during the move event + editorState.lastInteractionRect = { x, y, width, height }; +} + +function handleInteractionEnd() { + if (!editorState.isDrawing) return; + editorState.isDrawing = false; + + const finalRect = editorState.lastInteractionRect; + + if (!finalRect || finalRect.width < 5 || finalRect.height < 5) { + redrawShapes(); // Redraw to clear any invalid, tiny box + editorState.lastInteractionRect = null; + return; + } + + editorState.cropBoxes[editorState.currentPageNum - 1] = { + ...finalRect, + scale: editorState.scale + }; + + editorState.lastInteractionRect = null; // Reset for the next drawing action + redrawShapes(); +} + +export async function setupCanvasEditor(toolId: any) { + editorState.canvas = document.getElementById('canvas-editor'); + if (!editorState.canvas) return; + editorState.container = document.getElementById('canvas-container'); + editorState.context = editorState.canvas.getContext('2d'); + + const pageNav = document.getElementById('page-nav'); + const pdfData = await state.pdfDoc.save(); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + editorState.pdf = await pdfjsLib.getDocument({ data: pdfData }).promise; + + editorState.cropBoxes = {}; + editorState.currentPageNum = 1; + // @ts-expect-error TS(2322) FIXME: Type 'string' is not assignable to type 'number'. + editorState.scale = 'fit'; + + pageNav.textContent = ''; + + const prevButton = document.createElement('button'); + prevButton.id = 'prev-page'; + prevButton.className = 'btn p-2 rounded-full bg-gray-700 hover:bg-gray-600 disabled:opacity-50'; + prevButton.innerHTML = ''; + + const pageInfo = document.createElement('span'); + pageInfo.className = 'text-white font-medium'; + + const currentPageDisplay = document.createElement('span'); + currentPageDisplay.id = 'current-page-display'; + currentPageDisplay.textContent = '1'; + + pageInfo.append('Page ', currentPageDisplay, ` of ${editorState.pdf.numPages}`); + + const nextButton = document.createElement('button'); + nextButton.id = 'next-page'; + nextButton.className = 'btn p-2 rounded-full bg-gray-700 hover:bg-gray-600 disabled:opacity-50'; + nextButton.innerHTML = ''; + + pageNav.append(prevButton, pageInfo, nextButton); + + createIcons({icons}); + + document.getElementById('prev-page').addEventListener('click', () => { + if (editorState.currentPageNum > 1) queueRenderPage(editorState.currentPageNum - 1); + }); + document.getElementById('next-page').addEventListener('click', () => { + if (editorState.currentPageNum < editorState.pdf.numPages) queueRenderPage(editorState.currentPageNum + 1); + }); + + // To prevent stacking multiple listeners, we replace the canvas element with a clone + const newCanvas = editorState.canvas.cloneNode(true); + editorState.canvas.parentNode.replaceChild(newCanvas, editorState.canvas); + editorState.canvas = newCanvas; + editorState.context = newCanvas.getContext('2d'); + + // Mouse Events + editorState.canvas.addEventListener('mousedown', handleInteractionStart); + editorState.canvas.addEventListener('mousemove', handleInteractionMove); + editorState.canvas.addEventListener('mouseup', handleInteractionEnd); + editorState.canvas.addEventListener('mouseleave', handleInteractionEnd); + + // Touch Events + editorState.canvas.addEventListener('touchstart', handleInteractionStart, { passive: false }); + editorState.canvas.addEventListener('touchmove', handleInteractionMove, { passive: false }); + editorState.canvas.addEventListener('touchend', handleInteractionEnd); + + if (toolId === 'crop') { + document.getElementById('zoom-in-btn').onclick = () => { + editorState.scale += 0.25; + renderPage(editorState.currentPageNum); + }; + document.getElementById('zoom-out-btn').onclick = () => { + if (editorState.scale > 0.25) { + editorState.scale -= 0.25; + renderPage(editorState.currentPageNum); + } + }; + document.getElementById('fit-page-btn').onclick = async () => { + const page = await editorState.pdf.getPage(editorState.currentPageNum); + editorState.scale = calculateFitScale(page); + renderPage(editorState.currentPageNum); + }; + document.getElementById('clear-crop-btn').onclick = () => { + delete editorState.cropBoxes[editorState.currentPageNum - 1]; + redrawShapes(); + }; + document.getElementById('clear-all-crops-btn').onclick = () => { + editorState.cropBoxes = {}; + redrawShapes(); + }; + + document.getElementById('process-btn').onclick = async () => { + if (Object.keys(editorState.cropBoxes).length === 0) { + showAlert('No Area Selected', 'Please draw a rectangle on at least one page to select the crop area.'); + return; + } + const success = await toolLogic['crop-pdf'].process(editorState.cropBoxes); + if (success) { + showAlert('Success!', 'Your PDF has been cropped and the download has started.'); + } + }; + } + + queueRenderPage(1); +} \ No newline at end of file diff --git a/src/js/config/tesseract-languages.ts b/src/js/config/tesseract-languages.ts new file mode 100644 index 0000000..5b62368 --- /dev/null +++ b/src/js/config/tesseract-languages.ts @@ -0,0 +1,22 @@ +export const tesseractLanguages = { + "eng": "English", "afr": "Afrikaans", "amh": "Amharic", "ara": "Arabic", "asm": "Assamese", "aze": "Azerbaijani", + "aze_cyrl": "Azerbaijani - Cyrillic", "bel": "Belarusian", "ben": "Bengali", "bod": "Tibetan", "bos": "Bosnian", + "bul": "Bulgarian", "cat": "Catalan; Valencian", "ceb": "Cebuano", "ces": "Czech", "chi_sim": "Chinese - Simplified", + "chi_tra": "Chinese - Traditional", "chr": "Cherokee", "cym": "Welsh", "dan": "Danish", "deu": "German", + "dzo": "Dzongkha", "ell": "Greek, Modern (1453-)", "enm": "English, Middle (1100-1500)", "epo": "Esperanto", + "est": "Estonian", "eus": "Basque", "fas": "Persian", "fin": "Finnish", "fra": "French", "frk": "German Fraktur", + "frm": "French, Middle (ca. 1400-1600)", "gle": "Irish", "glg": "Galician", "grc": "Greek, Ancient (-1453)", + "guj": "Gujarati", "hat": "Haitian; Haitian Creole", "heb": "Hebrew", "hin": "Hindi", "hrv": "Croatian", + "hun": "Hungarian", "iku": "Inuktitut", "ind": "Indonesian", "isl": "Icelandic", "ita": "Italian", + "ita_old": "Italian - Old", "jav": "Javanese", "jpn": "Japanese", "kan": "Kannada", "kat": "Georgian", + "kat_old": "Georgian - Old", "kaz": "Kazakh", "khm": "Central Khmer", "kir": "Kirghiz; Kyrgyz", + "kor": "Korean", "kur": "Kurdish", "lao": "Lao", "lat": "Latin", "lav": "Latvian", "lit": "Lithuanian", + "mal": "Malayalam", "mar": "Marathi", "mkd": "Macedonian", "mlt": "Maltese", "msa": "Malay", "mya": "Burmese", + "nep": "Nepali", "nld": "Dutch; Flemish", "nor": "Norwegian", "ori": "Oriya", "pan": "Panjabi; Punjabi", + "pol": "Polish", "por": "Portuguese", "pus": "Pushto; Pashto", "ron": "Romanian; Moldavian; Moldovan", + "rus": "Russian", "san": "Sanskrit", "sin": "Sinhala; Sinhalese", "slk": "Slovak", "slv": "Slovenian", + "spa": "Spanish; Castilian", "spa_old": "Spanish; Castilian - Old", "sqi": "Albanian", "srp": "Serbian", + "srp_latn": "Serbian - Latin", "swa": "Swahili", "swe": "Swedish", "syr": "Syriac", "tam": "Tamil", "tel": "Telugu", + "tgk": "Tajik", "tgl": "Tagalog", "tha": "Thai", "tir": "Tigrinya", "tur": "Turkish", "uig": "Uighur; Uyghur", + "ukr": "Ukrainian", "urd": "Urdu", "uzb": "Uzbek", "uzb_cyrl": "Uzbek - Cyrillic", "vie": "Vietnamese", "yid": "Yiddish" +}; \ No newline at end of file diff --git a/src/js/config/tools.ts b/src/js/config/tools.ts new file mode 100644 index 0000000..260591e --- /dev/null +++ b/src/js/config/tools.ts @@ -0,0 +1,104 @@ +// This file centralizes the definition of all available tools, organized by category. +export const categories = [ + { + name: 'Popular Tools', + tools: [ + { id: 'merge', name: 'Merge PDF', icon: 'combine', subtitle: 'Combine multiple PDFs into one file.' }, + { id: 'split', name: 'Split PDF', icon: 'scissors', subtitle: 'Extract a range of pages into a new PDF.' }, + { id: 'compress', name: 'Compress PDF', icon: 'zap', subtitle: 'Reduce the file size of your PDF.' }, + { id: 'edit', name: 'PDF Editor', icon: 'pocket-knife', subtitle: 'Annotate, highlight, redact, comment, add shapes/images, search, and view PDFs' }, + { id: 'jpg-to-pdf', name: 'JPG to PDF', icon: 'image-up', subtitle: 'Create a PDF from one or more JPG images.' }, + { id: 'sign-pdf', name: 'Sign PDF', icon: 'pen-tool', subtitle: 'Draw, type, or upload your signature.' }, + { id: 'cropper', name: 'Crop PDF', icon: 'crop', subtitle: 'Trim the margins of every page in your PDF.' }, + { id: 'extract-pages', name: 'Extract Pages', icon: 'ungroup', subtitle: 'Save a selection of pages as new files.' }, + { id: 'duplicate-organize', name: 'Duplicate & Organize', icon: 'files', subtitle: 'Duplicate, reorder, and delete pages.' }, + { id: 'delete-pages', name: 'Delete Pages', icon: 'trash-2', subtitle: 'Remove specific pages from your document.' }, + ] + }, + { + name: 'Edit & Annotate', + tools: [ + { id: 'edit', name: 'PDF Editor', icon: 'pocket-knife', subtitle: 'Annotate, highlight, redact, comment, add shapes/images, search, and view PDFs.' }, + // { id: 'crop', name: 'Crop PDF', icon: 'crop', subtitle: 'Trim the margins of every page in your PDF.' }, + { id: 'add-page-numbers', name: 'Page Numbers', icon: 'list-ordered', subtitle: 'Insert page numbers into your document.' }, + { id: 'add-watermark', name: 'Add Watermark', icon: 'droplets', subtitle: 'Stamp text or an image over your PDF pages.' }, + { id: 'add-header-footer', name: 'Header & Footer', icon: 'pilcrow', subtitle: 'Add text to the top and bottom of pages.' }, + { id: 'invert-colors', name: 'Invert Colors', icon: 'contrast', subtitle: 'Create a "dark mode" version of your PDF.' }, + { id: 'change-background-color', name: 'Background Color', icon: 'palette', subtitle: 'Change the background color of your PDF.' }, + { id: 'change-text-color', name: 'Change Text Color', icon: 'type', subtitle: 'Change the color of text in your PDF.' }, + { id: 'sign-pdf', name: 'Sign PDF', icon: 'pen-tool', subtitle: 'Draw, type, or upload your signature.' }, + { id: 'remove-annotations', name: 'Remove Annotations', icon: 'eraser', subtitle: 'Strip comments, highlights, and links.' }, + { id: 'cropper', name: 'Crop PDF', icon: 'crop', subtitle: 'Trim the margins of every page in your PDF.' }, + { id: 'form-filler', name: 'PDF Form Filler', icon: 'square-pen', subtitle: 'Fill in forms directly in the browser.' }, + ] + }, + { + name: 'Convert to PDF', + tools: [ + { id: 'image-to-pdf', name: 'Image to PDF', icon: 'images', subtitle: 'Combine various images into one PDF.' }, + { id: 'jpg-to-pdf', name: 'JPG to PDF', icon: 'image-up', subtitle: 'Create a PDF from one or more JPG images.' }, + { id: 'png-to-pdf', name: 'PNG to PDF', icon: 'image-up', subtitle: 'Create a PDF from one or more PNG images.' }, + { id: 'webp-to-pdf', name: 'WebP to PDF', icon: 'image-up', subtitle: 'Create a PDF from one or more WebP images.' }, + { id: 'svg-to-pdf', name: 'SVG to PDF', icon: 'pen-tool', subtitle: 'Create a PDF from one or more SVG images.' }, + { id: 'bmp-to-pdf', name: 'BMP to PDF', icon: 'image', subtitle: 'Create a PDF from one or more BMP images.' }, + { id: 'heic-to-pdf', name: 'HEIC to PDF', icon: 'smartphone', subtitle: 'Create a PDF from one or more HEIC images.' }, + { id: 'tiff-to-pdf', name: 'TIFF to PDF', icon: 'layers', subtitle: 'Create a PDF from one or more TIFF images.' }, + { id: 'txt-to-pdf', name: 'Text to PDF', icon: 'file-pen', subtitle: 'Convert a plain text file into a PDF.' }, + // { id: 'md-to-pdf', name: 'Markdown to PDF', icon: 'file-text', subtitle: 'Convert a Markdown file into a PDF.' }, + // { id: 'scan-to-pdf', name: 'Scan to PDF', icon: 'camera', subtitle: 'Use your camera to create a scanned PDF.' }, + // { id: 'word-to-pdf', name: 'Word to PDF', icon: 'file-text', subtitle: 'Convert .docx documents to PDF.' }, + ] + }, + { + name: 'Convert from PDF', + tools: [ + { id: 'pdf-to-jpg', name: 'PDF to JPG', icon: 'file-image', subtitle: 'Convert each PDF page into a JPG image.' }, + { id: 'pdf-to-png', name: 'PDF to PNG', icon: 'file-image', subtitle: 'Convert each PDF page into a PNG image.' }, + { id: 'pdf-to-webp', name: 'PDF to WebP', icon: 'file-image', subtitle: 'Convert each PDF page into a WebP image.' }, + { id: 'pdf-to-bmp', name: 'PDF to BMP', icon: 'file-image', subtitle: 'Convert each PDF page into a BMP image.' }, + { id: 'pdf-to-tiff', name: 'PDF to TIFF', icon: 'file-image', subtitle: 'Convert each PDF page into a TIFF image.' }, + { id: 'pdf-to-greyscale', name: 'PDF to Greyscale', icon: 'palette', subtitle: 'Convert all colors to black and white.' }, + // { id: 'pdf-to-markdown', name: 'PDF to Markdown', icon: 'file-pen', subtitle: 'Extract text into a Markdown file.' }, + ] + }, + { + name: 'Organize & Manage', + tools: [ + { id: 'ocr-pdf', name: 'OCR PDF', icon: 'scan-text', subtitle: 'Make a PDF searchable and copyable.' }, + { id: 'merge', name: 'Merge PDF', icon: 'combine', subtitle: 'Combine multiple PDFs into one file.' }, + { id: 'organize', name: 'Organize PDF', icon: 'grip', subtitle: 'Reorder pages by dragging and dropping.' }, + { id: 'duplicate-organize', name: 'Duplicate & Organize', icon: 'files', subtitle: 'Duplicate, reorder, and delete pages.' }, + { id: 'split', name: 'Split PDF', icon: 'scissors', subtitle: 'Extract a range of pages into a new PDF.' }, + { id: 'split-in-half', name: 'Divide Pages', icon: 'table-columns-split', subtitle: 'Divide pages horizontally or vertically.' }, + { id: 'extract-pages', name: 'Extract Pages', icon: 'ungroup', subtitle: 'Save a selection of pages as new files.' }, + { id: 'delete-pages', name: 'Delete Pages', icon: 'trash-2', subtitle: 'Remove specific pages from your document.' }, + { id: 'add-blank-page', name: 'Add Blank Page', icon: 'file-plus-2', subtitle: 'Insert an empty page anywhere in your PDF.' }, + { id: 'reverse-pages', name: 'Reverse Pages', icon: 'arrow-down-z-a', subtitle: 'Flip the order of all pages in your document.' }, + { id: 'rotate', name: 'Rotate PDF', icon: 'rotate-cw', subtitle: 'Turn pages in 90-degree increments.' }, + { id: 'n-up', name: 'N-Up PDF', icon: 'layout-grid', subtitle: 'Arrange multiple pages onto a single sheet.' }, + { id: 'combine-single-page', name: 'Combine to Single Page', icon: 'unfold-vertical', subtitle: 'Stitch all pages into one continuous scroll.' }, + { id: 'view-metadata', name: 'View Metadata', icon: 'info', subtitle: 'Inspect the hidden properties of your PDF.' }, + { id: 'edit-metadata', name: 'Edit Metadata', icon: 'file-cog', subtitle: 'Change the author, title, and other properties.' }, + { id: 'pdf-to-zip', name: 'PDFs to ZIP', icon: 'stretch-horizontal', subtitle: 'Package multiple PDF files into a ZIP archive.' }, + { id: 'compare-pdfs', name: 'Compare PDFs', icon: 'git-compare', subtitle: 'Compare two PDFs side by side.' }, + ] + }, + { + name: 'Optimize & Repair', + tools: [ + { id: 'compress', name: 'Compress PDF', icon: 'zap', subtitle: 'Reduce the file size of your PDF.' }, + { id: 'fix-dimensions', name: 'Fix Page Size', icon: 'ruler-dimension-line', subtitle: 'Standardize all pages to a uniform size.' }, + { id: 'page-dimensions', name: 'Page Dimensions', icon: 'ruler', subtitle: 'Analyze page size, orientation, and units.' }, + ] + }, + { + name: 'Secure PDF', + tools: [ + { id: 'encrypt', name: 'Encrypt PDF', icon: 'lock', subtitle: 'Add a password to protect your PDF.' }, + { id: 'decrypt', name: 'Decrypt PDF', icon: 'unlock', subtitle: 'Remove password protection from a PDF.' }, + { id: 'flatten', name: 'Flatten PDF', icon: 'layers', subtitle: 'Make form fields and annotations non-editable.' }, + { id: 'remove-metadata', name: 'Remove Metadata', icon: 'file-x', subtitle: 'Strip hidden data from your PDF.' }, + { id: 'change-permissions', name: 'Change Permissions', icon: 'shield-check', subtitle: 'Set or change user permissions on a PDF.' }, + ] + }, +]; \ No newline at end of file diff --git a/src/js/handlers/fileHandler.ts b/src/js/handlers/fileHandler.ts new file mode 100644 index 0000000..6b7038d --- /dev/null +++ b/src/js/handlers/fileHandler.ts @@ -0,0 +1,613 @@ +// FILE: js/handlers/fileHandler.js + +import { state } from '../state.js'; +import { showLoader, hideLoader, showAlert, renderPageThumbnails, renderFileDisplay, switchView } from '../ui.js'; +import { readFileAsArrayBuffer } from '../utils/helpers.js'; +import { setupCanvasEditor } from '../canvasEditor.js'; +import { toolLogic } from '../logic/index.js'; +import { renderDuplicateOrganizeThumbnails } from '../logic/duplicate-organize.js'; +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; +import { icons, createIcons } from 'lucide'; +import Sortable from 'sortablejs'; + +async function handleSinglePdfUpload(toolId: any, file: any) { + showLoader('Loading PDF...'); + try { + const pdfBytes = await readFileAsArrayBuffer(file); + state.pdfDoc = await PDFLibDocument.load(pdfBytes as ArrayBuffer, { + ignoreEncryption: true + }); + hideLoader(); + + if (state.pdfDoc.isEncrypted && toolId !== 'decrypt' && toolId !== 'change-permissions') { + showAlert('Protected PDF', 'This PDF is password-protected. Please use the Decrypt or Change Permissions tool first.'); + switchView('grid'); + return; + } + + const optionsDiv = document.querySelector('[id$="-options"], [id$="-preview"], [id$="-organizer"], [id$="-rotator"], [id$="-editor"]'); + if (optionsDiv) optionsDiv.classList.remove('hidden'); + + const processBtn = document.getElementById('process-btn'); + if (processBtn) { + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + processBtn.disabled = false; + processBtn.classList.remove('hidden'); + const logic = toolLogic[toolId]; + if (logic) { + const func = typeof logic.process === 'function' ? logic.process : logic; + processBtn.onclick = func; + } + } + + if (['split', 'delete-pages', 'add-blank-page', 'extract-pages', 'add-header-footer'].includes(toolId)) { + document.getElementById('total-pages').textContent = state.pdfDoc.getPageCount(); + } + + if (toolId === 'organize' || toolId === 'rotate') { + await renderPageThumbnails(toolId, state.pdfDoc); + + if (toolId === 'rotate') { + const rotateAllControls = document.getElementById('rotate-all-controls'); + const rotateAllLeftBtn = document.getElementById('rotate-all-left-btn'); + const rotateAllRightBtn = document.getElementById('rotate-all-right-btn'); + + // Show the buttons + rotateAllControls.classList.remove('hidden'); + createIcons({icons}); // Render the new icons + + const rotateAll = (direction: any) => { + document.querySelectorAll('.page-rotator-item').forEach(item => { + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + const currentRotation = parseInt(item.dataset.rotation || '0'); + // Calculate new rotation, ensuring it wraps around 0-270 degrees + const newRotation = (currentRotation + (direction * 90) + 360) % 360; + + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + item.dataset.rotation = newRotation; + + const thumbnail = item.querySelector('canvas, img'); + if (thumbnail) { + // @ts-expect-error TS(2339) FIXME: Property 'style' does not exist on type 'Element'. + thumbnail.style.transform = `rotate(${newRotation}deg)`; + } + }); + }; + + rotateAllLeftBtn.onclick = () => rotateAll(-1); // -1 for counter-clockwise + rotateAllRightBtn.onclick = () => rotateAll(1); // 1 for clockwise + } + + } + + if (toolId === 'duplicate-organize') { + await renderDuplicateOrganizeThumbnails(); + } + if (['crop', 'redact'].includes(toolId)) { + await setupCanvasEditor(toolId); + } + + if (toolId === 'view-metadata') { + const resultsDiv = document.getElementById('metadata-results'); + showLoader('Analyzing full PDF metadata...'); + + try { + const pdfBytes = await readFileAsArrayBuffer(state.files[0]); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdfjsDoc = await pdfjsLib.getDocument({ data: pdfBytes }).promise; + + const [metadata, fieldObjects] = await Promise.all([ + pdfjsDoc.getMetadata(), + pdfjsDoc.getFieldObjects() + ]); + + const { info, metadata: rawXmpString } = metadata; + + const parsePdfDate = (pdfDate: any) => { + if (!pdfDate || typeof pdfDate !== 'string' || !pdfDate.startsWith('D:')) return pdfDate; + try { + const year = pdfDate.substring(2, 6); + const month = pdfDate.substring(6, 8); + const day = pdfDate.substring(8, 10); + const hour = pdfDate.substring(10, 12); + const minute = pdfDate.substring(12, 14); + const second = pdfDate.substring(14, 16); + return new Date(`${year}-${month}-${day}T${hour}:${minute}:${second}Z`).toLocaleString(); + } catch { + return pdfDate; + } + }; + + let htmlContent = ''; + + htmlContent += ` +
+

Info Dictionary

+
`; + + htmlContent += ` +
+

Interactive Form Fields

+
`; + + htmlContent += ` +
+

XMP Metadata (Raw XML)

+
`; + + if (rawXmpString) { + const escapedXml = rawXmpString.replace(/&/g, '&').replace(//g, '>'); + htmlContent += `
${escapedXml}
`; + } else { + htmlContent += `

- No XMP metadata found -

`; + } + htmlContent += `
`; + + resultsDiv.innerHTML = htmlContent; + resultsDiv.classList.remove('hidden'); + + } catch (e) { + console.error("Failed to view metadata or fields:", e); + showAlert('Error', 'Could not fully analyze the PDF. It may be corrupted or have an unusual structure.'); + } finally { + hideLoader(); + } + } + + if (toolId === 'edit-metadata') { + const form = document.getElementById('metadata-form'); + const formatDateForInput = (date: any) => { + if (!date) return ''; + const pad = (num: any) => num.toString().padStart(2, '0'); + return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`; + }; + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-title').value = state.pdfDoc.getTitle() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-author').value = state.pdfDoc.getAuthor() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-subject').value = state.pdfDoc.getSubject() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-keywords').value = state.pdfDoc.getKeywords() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-creator').value = state.pdfDoc.getCreator() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-producer').value = state.pdfDoc.getProducer() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-creation-date').value = formatDateForInput(state.pdfDoc.getCreationDate()); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-mod-date').value = formatDateForInput(state.pdfDoc.getModificationDate()); + + form.classList.remove('hidden'); + + const addBtn = document.getElementById('add-custom-meta-btn'); + const container = document.getElementById('custom-metadata-container'); + + addBtn.onclick = () => { + const newFieldId = `custom-field-${Date.now()}`; + const fieldWrapper = document.createElement('div'); + fieldWrapper.id = newFieldId; + fieldWrapper.className = 'flex items-center gap-2'; + fieldWrapper.innerHTML = ` + + + + `; + container.appendChild(fieldWrapper); + + createIcons({icons}); // Re-render icons + }; + + createIcons({icons}); + } + if (toolId === 'edit-metadata') { + const form = document.getElementById('metadata-form'); + const container = document.getElementById('custom-metadata-container'); + const addBtn = document.getElementById('add-custom-meta-btn'); + + // Helper to format Date objects + const formatDateForInput = (date: any) => { + if (!date) return ''; + const pad = (num: any) => num.toString().padStart(2, '0'); + return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`; + }; + + + + // Comprehensive decoder for PDF values + const decodePDFValue = (valueNode: any) => { + if (!valueNode) return ''; + + // @ts-expect-error TS(2339) FIXME: Property 'PDFLib' does not exist on type 'Window &... Remove this comment to see the full error message + const { PDFHexString, PDFString, PDFName, PDFNumber } = window.PDFLib; + + try { + // Handle PDFHexString + if (valueNode instanceof PDFHexString) { + // Try the built-in decoder first + try { + return valueNode.decodeText(); + } catch (e) { + console.warn('Built-in decodeText failed for PDFHexString, trying manual decode'); + // Manual hex decoding + const hexStr = valueNode.toString(); + return decodeHexStringManual(hexStr); + } + } + + // Handle PDFString + if (valueNode instanceof PDFString) { + try { + return valueNode.decodeText(); + } catch (e) { + console.warn('Built-in decodeText failed for PDFString, using toString'); + return valueNode.toString(); + } + } + + // Handle other types + if (valueNode instanceof PDFName) { + return valueNode.decodeText ? valueNode.decodeText() : valueNode.toString(); + } + + if (valueNode instanceof PDFNumber) { + return valueNode.toString(); + } + + // Fallback - check if the toString() result needs hex decoding + const strValue = valueNode.toString(); + + // Check for various hex encoding patterns + if (strValue.includes('#')) { + // Pattern like "helllo#20h" + return strValue.replace(/#([0-9A-Fa-f]{2})/g, (match: any, hex: any) => { + return String.fromCharCode(parseInt(hex, 16)); + }); + } + + // Check if it's a hex string in angle brackets like <48656C6C6C6F20> + if (strValue.match(/^<[0-9A-Fa-f\s]+>$/)) { + return decodeHexStringManual(strValue); + } + + // Check if it's a parentheses-wrapped string + if (strValue.match(/^\([^)]*\)$/)) { + return strValue.slice(1, -1); // Remove parentheses + } + + return strValue; + + } catch (error) { + console.error('Error decoding PDF value:', error); + return valueNode.toString(); + } + }; + + // Manual hex string decoder + const decodeHexStringManual = (hexStr: any) => { + try { + // Remove angle brackets if present + let cleanHex = hexStr.replace(/^<|>$/g, ''); + // Remove any whitespace + cleanHex = cleanHex.replace(/\s/g, ''); + + let result = ''; + for (let i = 0; i < cleanHex.length; i += 2) { + const hexPair = cleanHex.substr(i, 2); + if (hexPair.length === 2 && /^[0-9A-Fa-f]{2}$/.test(hexPair)) { + const charCode = parseInt(hexPair, 16); + // Only add printable characters or common whitespace + if (charCode >= 32 && charCode <= 126) { + result += String.fromCharCode(charCode); + } else if (charCode === 10 || charCode === 13 || charCode === 9) { + result += String.fromCharCode(charCode); + } else { + // For non-printable characters, you might want to skip or use a placeholder + result += String.fromCharCode(charCode); + } + } + } + return result; + } catch (error) { + console.error('Manual hex decode failed:', error); + return hexStr; + } + }; + + // --- 1. Pre-fill Standard Fields --- + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-title').value = state.pdfDoc.getTitle() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-author').value = state.pdfDoc.getAuthor() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-subject').value = state.pdfDoc.getSubject() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-keywords').value = state.pdfDoc.getKeywords() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-creator').value = state.pdfDoc.getCreator() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-producer').value = state.pdfDoc.getProducer() || ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-creation-date').value = formatDateForInput(state.pdfDoc.getCreationDate()); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('meta-mod-date').value = formatDateForInput(state.pdfDoc.getModificationDate()); + + container.querySelectorAll('.custom-field-wrapper').forEach(el => el.remove()); + + addBtn.onclick = () => { + const newFieldId = `custom-field-${Date.now()}`; + const fieldWrapper = document.createElement('div'); + fieldWrapper.id = newFieldId; + fieldWrapper.className = 'flex items-center gap-2 custom-field-wrapper'; + fieldWrapper.innerHTML = ` + + + + `; + container.appendChild(fieldWrapper); + + createIcons({icons}); + }; + + form.classList.remove('hidden'); + + createIcons({icons}); // Render all icons after dynamic changes + } + + if (toolId === 'cropper') { + document.getElementById('cropper-ui-container').classList.remove('hidden'); + } + + if (toolId === 'page-dimensions') { + toolLogic['page-dimensions'](); + } + + if (toolLogic[toolId] && typeof toolLogic[toolId].setup === 'function') { + toolLogic[toolId].setup(); + } + } catch (e) { + hideLoader(); + showAlert('Error', 'Could not load PDF. The file may be invalid, corrupted, or password-protected.'); + console.error(e); + } +} + +function handleMultiFileUpload(toolId: any) { + const processBtn = document.getElementById('process-btn'); + if (processBtn) { + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + processBtn.disabled = false; + const logic = toolLogic[toolId]; + if (logic) { + const func = typeof logic.process === 'function' ? logic.process : logic; + processBtn.onclick = func; + } + } + + if (toolId === 'merge') { + toolLogic.merge.setup(); + } else if (toolId === 'image-to-pdf') { + const imageList = document.getElementById('image-list'); + + imageList.innerHTML = ''; + + state.files.forEach(file => { + const url = URL.createObjectURL(file); + const li = document.createElement('li'); + li.className = "relative group cursor-move"; + li.dataset.fileName = file.name; + li.innerHTML = `

${file.name}

`; + imageList.appendChild(li); + }); + + Sortable.create(imageList); + } +} + + +export function setupFileInputHandler(toolId: any) { + const fileInput = document.getElementById('file-input'); + const multiFileTools = ['merge', 'pdf-to-zip', 'jpg-to-pdf', 'png-to-pdf', 'webp-to-pdf', 'image-to-pdf', 'svg-to-pdf', 'bmp-to-pdf', 'heic-to-pdf', 'tiff-to-pdf']; + const isMultiFileTool = multiFileTools.includes(toolId); + let isFirstUpload = true; + + const processFiles = async (newFiles: any) => { + if (newFiles.length === 0) return; + + if (!isMultiFileTool || isFirstUpload) { + state.files = newFiles; + } else { + state.files = [...state.files, ...newFiles]; + } + isFirstUpload = false; + + const fileDisplayArea = document.getElementById('file-display-area'); + if (fileDisplayArea) { + renderFileDisplay(fileDisplayArea, state.files); + } + + const fileControls = document.getElementById('file-controls'); + if (fileControls) { + fileControls.classList.remove('hidden'); + + createIcons({icons}); + } + + const singlePdfLoadTools = ['split', 'organize', 'rotate', 'add-page-numbers', + 'pdf-to-jpg', 'pdf-to-png', 'pdf-to-webp', 'compress', 'pdf-to-greyscale', + 'edit-metadata', 'remove-metadata', 'flatten', 'delete-pages', 'add-blank-page', + 'extract-pages', 'add-watermark', 'add-header-footer', 'invert-colors', 'view-metadata', + 'reverse-pages', 'crop', 'redact', 'pdf-to-bmp', 'pdf-to-tiff', 'split-in-half', + 'page-dimensions', 'n-up', 'duplicate-organize', 'combine-single-page', 'fix-dimensions', 'change-background-color', + 'change-text-color', 'ocr-pdf', 'sign-pdf', 'remove-annotations', 'cropper', 'form-filler', + ]; + const simpleTools = ['encrypt', 'decrypt', 'change-permissions', 'pdf-to-markdown', 'word-to-pdf']; + + if (isMultiFileTool) { + handleMultiFileUpload(toolId); + } else if (singlePdfLoadTools.includes(toolId)) { + await handleSinglePdfUpload(toolId, state.files[0]); + } else if (simpleTools.includes(toolId)) { + const optionsDivId = toolId === 'change-permissions' ? 'permissions-options' : `${toolId}-options`; + const optionsDiv = document.getElementById(optionsDivId); + if (optionsDiv) optionsDiv.classList.remove('hidden'); + const processBtn = document.getElementById('process-btn'); + if (processBtn) { + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + processBtn.disabled = false; + processBtn.onclick = () => { + const logic = toolLogic[toolId]; + if (logic) { + const func = typeof logic.process === 'function' ? logic.process : logic; + func(); + } + }; + } + } + else if (toolId === 'edit') { + const file = state.files[0]; + if (!file) return; + + const pdfWrapper = document.getElementById('embed-pdf-wrapper'); + const pdfContainer = document.getElementById('embed-pdf-container'); + + pdfContainer.innerHTML = ''; + + if (state.currentPdfUrl) { + URL.revokeObjectURL(state.currentPdfUrl); + } + + pdfWrapper.classList.remove('hidden'); + + const fileURL = URL.createObjectURL(file); + + state.currentPdfUrl = fileURL; + + const script = document.createElement('script'); + script.type = 'module'; + script.innerHTML = ` + import EmbedPDF from 'https://snippet.embedpdf.com/embedpdf.js'; + EmbedPDF.init({ + type: 'container', + target: document.getElementById('embed-pdf-container'), + src: '${fileURL}', + theme: 'dark', + }); + `; + document.head.appendChild(script); + + const backBtn = document.getElementById('back-to-grid'); + const urlRevoker = () => { + URL.revokeObjectURL(fileURL); + state.currentPdfUrl = null; // Clear from state as well + backBtn.removeEventListener('click', urlRevoker); + }; + backBtn.addEventListener('click', urlRevoker); + } + }; + + // @ts-expect-error TS(2339) FIXME: Property 'files' does not exist on type 'EventTarg... Remove this comment to see the full error message + fileInput.addEventListener('change', (e) => processFiles(Array.from(e.target.files))); + + const setupAddMoreButton = () => { + const addMoreBtn = document.getElementById('add-more-btn'); + if (addMoreBtn) { + addMoreBtn.addEventListener('click', () => { + fileInput.click(); + }); + } + }; + + const setupClearButton = () => { + const clearBtn = document.getElementById('clear-files-btn'); + if (clearBtn) { + clearBtn.addEventListener('click', () => { + state.files = []; + isFirstUpload = true; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + fileInput.value = ''; + + const fileDisplayArea = document.getElementById('file-display-area'); + if (fileDisplayArea) fileDisplayArea.innerHTML = ''; + + const fileControls = document.getElementById('file-controls'); + if (fileControls) fileControls.classList.add('hidden'); + + // Clear tool-specific UI + const toolSpecificUI = ['file-list', 'page-merge-preview', 'image-list']; + toolSpecificUI.forEach(id => { + const el = document.getElementById(id); + if (el) el.innerHTML = ''; + }); + + const processBtn = document.getElementById('process-btn'); + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + if (processBtn) processBtn.disabled = true; + }); + } + }; + + setTimeout(() => { + setupAddMoreButton(); + setupClearButton(); + }, 100); +} \ No newline at end of file diff --git a/src/js/handlers/toolSelectionHandler.ts b/src/js/handlers/toolSelectionHandler.ts new file mode 100644 index 0000000..1c0c054 --- /dev/null +++ b/src/js/handlers/toolSelectionHandler.ts @@ -0,0 +1,41 @@ +import { state } from '../state.js'; +import { dom, switchView, toolTemplates } from '../ui.js'; +import { setupFileInputHandler } from './fileHandler.js'; +import { toolLogic } from '../logic/index.js'; +import { createIcons, icons } from 'lucide'; + +const SETUP_AFTER_UPLOAD = ['sign-pdf']; + +export function setupToolInterface(toolId: any) { + window.scrollTo({ + top: 0, + left: 0, + behavior: 'instant' as ScrollBehavior + }); + + state.activeTool = toolId; + dom.toolContent.innerHTML = toolTemplates[toolId](); + createIcons({icons}); + switchView('tool'); + + const fileInput = document.getElementById('file-input'); + const processBtn = document.getElementById('process-btn'); + + if (!fileInput && processBtn) { + const logic = toolLogic[toolId]; + if (logic) { + const func = typeof logic.process === 'function' ? logic.process : logic; + processBtn.onclick = func; + } + } + + if (toolLogic[toolId] && typeof toolLogic[toolId].setup === 'function') { + if (!SETUP_AFTER_UPLOAD.includes(toolId)) { + toolLogic[toolId].setup(); + } + } + + if (fileInput) { + setupFileInputHandler(toolId); + } +} \ No newline at end of file diff --git a/src/js/logic/add-blank-page.ts b/src/js/logic/add-blank-page.ts new file mode 100644 index 0000000..17dc18b --- /dev/null +++ b/src/js/logic/add-blank-page.ts @@ -0,0 +1,50 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function addBlankPage() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const pageNumberInput = document.getElementById('page-number').value; + if (pageNumberInput.trim() === '') { + showAlert('Invalid Input', 'Please enter a page number.'); + return; + } + + const position = parseInt(pageNumberInput); + const totalPages = state.pdfDoc.getPageCount(); + if (isNaN(position) || position < 0 || position > totalPages) { + showAlert('Invalid Input', `Please enter a number between 0 and ${totalPages}.`); + return; + } + + showLoader('Adding page...'); + try { + const newPdf = await PDFLibDocument.create(); + const { width, height } = state.pdfDoc.getPage(0).getSize(); + const allIndices = Array.from({ length: totalPages }, (_, i) => i); + + const indicesBefore = allIndices.slice(0, position); + const indicesAfter = allIndices.slice(position); + + if (indicesBefore.length > 0) { + const copied = await newPdf.copyPages(state.pdfDoc, indicesBefore); + copied.forEach((p: any) => newPdf.addPage(p)); + } + + newPdf.addPage([width, height]); + + if (indicesAfter.length > 0) { + const copied = await newPdf.copyPages(state.pdfDoc, indicesAfter); + copied.forEach((p: any) => newPdf.addPage(p)); + } + + const newPdfBytes = await newPdf.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'page-added.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not add a blank page.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/add-header-footer.ts b/src/js/logic/add-header-footer.ts new file mode 100644 index 0000000..3197889 --- /dev/null +++ b/src/js/logic/add-header-footer.ts @@ -0,0 +1,101 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, hexToRgb, parsePageRanges } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument, rgb, StandardFonts } from 'pdf-lib'; + + +export function setupHeaderFooterUI() { + const totalPagesSpan = document.getElementById('total-pages'); + if (totalPagesSpan && state.pdfDoc) { + totalPagesSpan.textContent = state.pdfDoc.getPageCount(); + } +} + +export async function addHeaderFooter() { + showLoader('Adding header & footer...'); + try { + const helveticaFont = await state.pdfDoc.embedFont(StandardFonts.Helvetica); + const allPages = state.pdfDoc.getPages(); + const totalPages = allPages.length; + const margin = 40; + + // --- 1. Get new formatting options from the UI --- + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const fontSize = parseInt(document.getElementById('font-size').value) || 10; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const colorHex = document.getElementById('font-color').value; + const fontColor = hexToRgb(colorHex); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const pageRangeInput = document.getElementById('page-range').value; + + // --- 2. Get text values --- + const texts = { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + headerLeft: document.getElementById('header-left').value, + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + headerCenter: document.getElementById('header-center').value, + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + headerRight: document.getElementById('header-right').value, + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + footerLeft: document.getElementById('footer-left').value, + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + footerCenter: document.getElementById('footer-center').value, + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + footerRight: document.getElementById('footer-right').value, + }; + + // --- 3. Parse page range to determine which pages to modify --- + const indicesToProcess = parsePageRanges(pageRangeInput, totalPages); + if (indicesToProcess.length === 0) { + throw new Error("Invalid page range specified. Please check your input (e.g., '1-3, 5')."); + } + + // --- 4. Define drawing options with new values --- + const drawOptions = { + font: helveticaFont, + size: fontSize, + color: rgb(fontColor.r, fontColor.g, fontColor.b) + }; + + // --- 5. Loop over only the selected pages --- + for (const pageIndex of indicesToProcess) { + // @ts-expect-error TS(2538) FIXME: Type 'unknown' cannot be used as an index type. + const page = allPages[pageIndex]; + const { width, height } = page.getSize(); + // @ts-expect-error TS(2365) FIXME: Operator '+' cannot be applied to types 'unknown' ... Remove this comment to see the full error message + const pageNumber = pageIndex + 1; // For dynamic text + + // Helper to replace placeholders like {page} and {total} + const processText = (text: any) => text + .replace(/{page}/g, pageNumber) + .replace(/{total}/g, totalPages); + + // Get processed text for the current page + const processedTexts = { + headerLeft: processText(texts.headerLeft), + headerCenter: processText(texts.headerCenter), + headerRight: processText(texts.headerRight), + footerLeft: processText(texts.footerLeft), + footerCenter: processText(texts.footerCenter), + footerRight: processText(texts.footerRight), + }; + + if (processedTexts.headerLeft) page.drawText(processedTexts.headerLeft, { ...drawOptions, x: margin, y: height - margin }); + if (processedTexts.headerCenter) page.drawText(processedTexts.headerCenter, { ...drawOptions, x: (width / 2) - helveticaFont.widthOfTextAtSize(processedTexts.headerCenter, fontSize) / 2, y: height - margin }); + if (processedTexts.headerRight) page.drawText(processedTexts.headerRight, { ...drawOptions, x: width - margin - helveticaFont.widthOfTextAtSize(processedTexts.headerRight, fontSize), y: height - margin }); + if (processedTexts.footerLeft) page.drawText(processedTexts.footerLeft, { ...drawOptions, x: margin, y: margin }); + if (processedTexts.footerCenter) page.drawText(processedTexts.footerCenter, { ...drawOptions, x: (width / 2) - helveticaFont.widthOfTextAtSize(processedTexts.footerCenter, fontSize) / 2, y: margin }); + if (processedTexts.footerRight) page.drawText(processedTexts.footerRight, { ...drawOptions, x: width - margin - helveticaFont.widthOfTextAtSize(processedTexts.footerRight, fontSize), y: margin }); + } + + const newPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'header-footer-added.pdf'); + + } catch (e) { + console.error(e); + showAlert('Error', e.message || 'Could not add header or footer.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/add-page-numbers.ts b/src/js/logic/add-page-numbers.ts new file mode 100644 index 0000000..2a12ce5 --- /dev/null +++ b/src/js/logic/add-page-numbers.ts @@ -0,0 +1,101 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, hexToRgb } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { rgb, StandardFonts } from 'pdf-lib'; + +export async function addPageNumbers() { + showLoader('Adding page numbers...'); + try { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const position = document.getElementById('position').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const fontSize = parseInt(document.getElementById('font-size').value) || 12; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const format = document.getElementById('number-format').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const colorHex = document.getElementById('text-color').value; + const textColor = hexToRgb(colorHex); + + const pages = state.pdfDoc.getPages(); + const totalPages = pages.length; + const helveticaFont = await state.pdfDoc.embedFont(StandardFonts.Helvetica); + + for (let i = 0; i < totalPages; i++) { + const page = pages[i]; + + const mediaBox = page.getMediaBox(); + const cropBox = page.getCropBox(); + const bounds = cropBox || mediaBox; + const width = bounds.width; + const height = bounds.height; + const xOffset = bounds.x || 0; + const yOffset = bounds.y || 0; + + let pageNumText = (format === 'page_x_of_y') ? `${i + 1} / ${totalPages}` : `${i + 1}`; + + const textWidth = helveticaFont.widthOfTextAtSize(pageNumText, fontSize); + const textHeight = fontSize; + + const minMargin = 8; + const maxMargin = 40; + const marginPercentage = 0.04; + + const horizontalMargin = Math.max(minMargin, Math.min(maxMargin, width * marginPercentage)); + const verticalMargin = Math.max(minMargin, Math.min(maxMargin, height * marginPercentage)); + + // Ensure text doesn't go outside visible page boundaries + const safeHorizontalMargin = Math.max(horizontalMargin, textWidth / 2 + 3); + const safeVerticalMargin = Math.max(verticalMargin, textHeight + 3); + + let x, y; + + switch (position) { + case 'bottom-center': + x = Math.max(safeHorizontalMargin, Math.min(width - safeHorizontalMargin - textWidth, (width - textWidth) / 2)) + xOffset; + y = safeVerticalMargin + yOffset; + break; + case 'bottom-left': + x = safeHorizontalMargin + xOffset; + y = safeVerticalMargin + yOffset; + break; + case 'bottom-right': + x = Math.max(safeHorizontalMargin, width - safeHorizontalMargin - textWidth) + xOffset; + y = safeVerticalMargin + yOffset; + break; + case 'top-center': + x = Math.max(safeHorizontalMargin, Math.min(width - safeHorizontalMargin - textWidth, (width - textWidth) / 2)) + xOffset; + y = height - safeVerticalMargin - textHeight + yOffset; + break; + case 'top-left': + x = safeHorizontalMargin + xOffset; + y = height - safeVerticalMargin - textHeight + yOffset; + break; + case 'top-right': + x = Math.max(safeHorizontalMargin, width - safeHorizontalMargin - textWidth) + xOffset; + y = height - safeVerticalMargin - textHeight + yOffset; + break; + } + + // Final safety check to ensure coordinates are within visible page bounds + x = Math.max(xOffset + 3, Math.min(xOffset + width - textWidth - 3, x)); + y = Math.max(yOffset + 3, Math.min(yOffset + height - textHeight - 3, y)); + + page.drawText(pageNumText, { + x, y, + font: helveticaFont, + size: fontSize, + color: rgb(textColor.r, textColor.g, textColor.b) + }); + } + + const newPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'paginated.pdf'); + showAlert('Success', 'Page numbers added successfully!'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not add page numbers.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/add-watermark.ts b/src/js/logic/add-watermark.ts new file mode 100644 index 0000000..b08eb6d --- /dev/null +++ b/src/js/logic/add-watermark.ts @@ -0,0 +1,132 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer, hexToRgb } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument, rgb, degrees, StandardFonts } from 'pdf-lib'; + +export function setupWatermarkUI() { + const watermarkTypeRadios = document.querySelectorAll('input[name="watermark-type"]'); + const textOptions = document.getElementById('text-watermark-options'); + const imageOptions = document.getElementById('image-watermark-options'); + + watermarkTypeRadios.forEach(radio => { + radio.addEventListener('change', (e) => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'EventTarg... Remove this comment to see the full error message + if (e.target.value === 'text') { + textOptions.classList.remove('hidden'); + imageOptions.classList.add('hidden'); + } else { + textOptions.classList.add('hidden'); + imageOptions.classList.remove('hidden'); + } + }); + }); + + const opacitySliderText = document.getElementById('opacity-text'); + const opacityValueText = document.getElementById('opacity-value-text'); + const angleSliderText = document.getElementById('angle-text'); + const angleValueText = document.getElementById('angle-value-text'); + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + opacitySliderText.addEventListener('input', () => opacityValueText.textContent = opacitySliderText.value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + angleSliderText.addEventListener('input', () => angleValueText.textContent = angleSliderText.value); + + const opacitySliderImage = document.getElementById('opacity-image'); + const opacityValueImage = document.getElementById('opacity-value-image'); + const angleSliderImage = document.getElementById('angle-image'); + const angleValueImage = document.getElementById('angle-value-image'); + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + opacitySliderImage.addEventListener('input', () => opacityValueImage.textContent = opacitySliderImage.value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + angleSliderImage.addEventListener('input', () => angleValueImage.textContent = angleSliderImage.value); +} + +export async function addWatermark() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + const watermarkType = document.querySelector('input[name="watermark-type"]:checked').value; + + showLoader('Adding watermark...'); + + try { + const pages = state.pdfDoc.getPages(); + let watermarkAsset = null; + + if (watermarkType === 'text') { + watermarkAsset = await state.pdfDoc.embedFont(StandardFonts.Helvetica); + } else { // 'image' + // @ts-expect-error TS(2339) FIXME: Property 'files' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const imageFile = document.getElementById('image-watermark-input').files[0]; + if (!imageFile) throw new Error('Please select an image file for the watermark.'); + + const imageBytes = await readFileAsArrayBuffer(imageFile); + if (imageFile.type === 'image/png') { + watermarkAsset = await state.pdfDoc.embedPng(imageBytes); + } else if (imageFile.type === 'image/jpeg') { + watermarkAsset = await state.pdfDoc.embedJpg(imageBytes); + } else { + throw new Error('Unsupported Image. Please use a PNG or JPG for the watermark.'); + } + } + + for (const page of pages) { + const { width, height } = page.getSize(); + + if (watermarkType === 'text') { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const text = document.getElementById('watermark-text').value; + if (!text.trim()) throw new Error('Please enter text for the watermark.'); + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const fontSize = parseInt(document.getElementById('font-size').value) || 72; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const angle = parseInt(document.getElementById('angle-text').value) || 0; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const opacity = parseFloat(document.getElementById('opacity-text').value) || 0.3; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const colorHex = document.getElementById('text-color').value; + const textColor = hexToRgb(colorHex); + const textWidth = watermarkAsset.widthOfTextAtSize(text, fontSize); + + page.drawText(text, { + x: (width - textWidth) / 2, + y: height / 2, + font: watermarkAsset, + size: fontSize, + color: rgb(textColor.r, textColor.g, textColor.b), + opacity: opacity, + rotate: degrees(angle), + }); + + } else { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const angle = parseInt(document.getElementById('angle-image').value) || 0; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const opacity = parseFloat(document.getElementById('opacity-image').value) || 0.3; + + const scale = 0.5; + const imgWidth = watermarkAsset.width * scale; + const imgHeight = watermarkAsset.height * scale; + + page.drawImage(watermarkAsset, { + x: (width - imgWidth) / 2, + y: (height - imgHeight) / 2, + width: imgWidth, + height: imgHeight, + opacity: opacity, + rotate: degrees(angle), + }); + } + } + + const newPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'watermarked.pdf'); + + } catch (e) { + console.error(e); + showAlert('Error', e.message || 'Could not add the watermark. Please check your inputs.'); + } finally { + hideLoader(); + } +} diff --git a/src/js/logic/bmp-to-pdf.ts b/src/js/logic/bmp-to-pdf.ts new file mode 100644 index 0000000..d99d3ec --- /dev/null +++ b/src/js/logic/bmp-to-pdf.ts @@ -0,0 +1,55 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +async function convertImageToPngBytes(file: any) { + return new Promise((resolve, reject) => { + const img = new Image(); + const reader = new FileReader(); + + reader.onload = (e) => { + img.onload = async () => { + const canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + const pngBlob = await new Promise(res => canvas.toBlob(res, 'image/png')); + // @ts-expect-error TS(2339) FIXME: Property 'arrayBuffer' does not exist on type 'unk... Remove this comment to see the full error message + const pngBytes = await pngBlob.arrayBuffer(); + resolve(pngBytes); + }; + img.onerror = () => reject(new Error('Failed to load image.')); + // @ts-expect-error TS(2322) FIXME: Type 'string | ArrayBuffer' is not assignable to t... Remove this comment to see the full error message + img.src = e.target.result; + }; + reader.onerror = () => reject(new Error('Failed to read file.')); + reader.readAsDataURL(file); + }); +} + +export async function bmpToPdf() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select at least one BMP file.'); + return; + } + showLoader('Converting BMP to PDF...'); + try { + const pdfDoc = await PDFLibDocument.create(); + for (const file of state.files) { + const pngBytes = await convertImageToPngBytes(file); + const pngImage = await pdfDoc.embedPng(pngBytes as ArrayBuffer); + const page = pdfDoc.addPage([pngImage.width, pngImage.height]); + page.drawImage(pngImage, { x: 0, y: 0, width: pngImage.width, height: pngImage.height }); + } + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'from_bmps.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert BMP to PDF. One of the files may be invalid.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/change-background-color.ts b/src/js/logic/change-background-color.ts new file mode 100644 index 0000000..9f56f9e --- /dev/null +++ b/src/js/logic/change-background-color.ts @@ -0,0 +1,53 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, hexToRgb } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument, rgb } from 'pdf-lib'; + +export async function changeBackgroundColor() { + if (!state.pdfDoc) { + showAlert('Error', 'PDF not loaded.'); + return; + } + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const colorHex = document.getElementById('background-color').value; + const color = hexToRgb(colorHex); + + showLoader('Changing background color...'); + try { + const newPdfDoc = await PDFLibDocument.create(); + + for (let i = 0; i < state.pdfDoc.getPageCount(); i++) { + const [originalPage] = await newPdfDoc.copyPages(state.pdfDoc, [i]); + const { width, height } = originalPage.getSize(); + + const newPage = newPdfDoc.addPage([width, height]); + + newPage.drawRectangle({ + x: 0, + y: 0, + width, + height, + color: rgb(color.r, color.g, color.b), + }); + + const embeddedPage = await newPdfDoc.embedPage(originalPage); + newPage.drawPage(embeddedPage, { + x: 0, + y: 0, + width, + height, + }); + } + + const newPdfBytes = await newPdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'background-changed.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not change the background color.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/change-permissions.ts b/src/js/logic/change-permissions.ts new file mode 100644 index 0000000..147630d --- /dev/null +++ b/src/js/logic/change-permissions.ts @@ -0,0 +1,121 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import PDFDocument from 'pdfkit/js/pdfkit.standalone'; +import blobStream from 'blob-stream'; +import * as pdfjsLib from "pdfjs-dist"; + +export async function changePermissions() { + // --- 1. GATHER INPUTS FROM THE NEW UI --- + const currentPassword = (document.getElementById('current-password') as HTMLInputElement).value; + const newUserPassword = (document.getElementById('new-user-password') as HTMLInputElement).value; + const newOwnerPassword = (document.getElementById('new-owner-password') as HTMLInputElement).value; + + // An owner password is required to enforce any permissions. + if (!newOwnerPassword && (newUserPassword || document.querySelectorAll('input[type="checkbox"]:not(:checked)').length > 0)) { + showAlert('Input Required', 'You must set a "New Owner Password" to enforce specific permissions or to set a user password.'); + return; + } + + showLoader('Preparing to process...'); + + try { + const file = state.files[0]; + const pdfData = await readFileAsArrayBuffer(file); + + // --- 2. UNLOCK PDF WITH CURRENT PASSWORD --- + let pdf; + try { + pdf = await pdfjsLib.getDocument({ + data: pdfData as ArrayBuffer, + password: currentPassword + }).promise; + } catch (e) { + // This catch is specific to password errors in pdf.js + if (e.name === 'PasswordException') { + hideLoader(); + showAlert('Incorrect Password', 'The current password you entered is incorrect.'); + return; + } + throw e; // Re-throw other errors + } + + // --- 3. RASTERIZE PAGES (UNCHANGED LOGIC) --- + const numPages = pdf.numPages; + const pageImages = []; + + for (let i = 1; i <= numPages; i++) { + document.getElementById('loader-text').textContent = `Processing page ${i} of ${numPages}...`; + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2.0 }); + const canvas = document.createElement('canvas'); + canvas.height = viewport.height; + canvas.width = viewport.width; + const context = canvas.getContext('2d'); + await page.render({ canvasContext: context, viewport: viewport }).promise; + pageImages.push({ + data: canvas.toDataURL('image/jpeg', 0.8), + width: viewport.width, + height: viewport.height + }); + } + + document.getElementById('loader-text').textContent = 'Applying new permissions...'; + + // --- 4. GATHER ALL PERMISSION CHECKBOX VALUES --- + const allowPrinting = (document.getElementById('allow-printing') as HTMLInputElement).checked; + const allowCopying = (document.getElementById('allow-copying') as HTMLInputElement).checked; + const allowModifying = (document.getElementById('allow-modifying') as HTMLInputElement).checked; + const allowAnnotating = (document.getElementById('allow-annotating') as HTMLInputElement).checked; + const allowFillingForms = (document.getElementById('allow-filling-forms') as HTMLInputElement).checked; + const allowContentAccessibility = (document.getElementById('allow-content-accessibility') as HTMLInputElement).checked; + const allowDocumentAssembly = (document.getElementById('allow-document-assembly') as HTMLInputElement).checked; + + // --- 5. CREATE NEW PDF WITH PDFKIT USING ALL NEW SETTINGS --- + const doc = new PDFDocument({ + size: [pageImages[0].width, pageImages[0].height], + pdfVersion: '1.7ext3', // Use 256-bit AES encryption + + // Apply the new, separate user and owner passwords + userPassword: newUserPassword, + ownerPassword: newOwnerPassword, + + // Apply all seven permissions from the checkboxes + permissions: { + printing: allowPrinting ? 'highResolution' : false, + modifying: allowModifying, + copying: allowCopying, + annotating: allowAnnotating, + fillingForms: allowFillingForms, + contentAccessibility: allowContentAccessibility, + documentAssembly: allowDocumentAssembly + } + }); + + const stream = doc.pipe(blobStream()); + + for (let i = 0; i < pageImages.length; i++) { + if (i > 0) doc.addPage({ size: [pageImages[i].width, pageImages[i].height] }); + doc.image(pageImages[i].data, 0, 0, { + width: pageImages[i].width, + height: pageImages[i].height + }); + } + + doc.end(); + + // --- 6. FINALIZE AND DOWNLOAD (UNCHANGED LOGIC) --- + stream.on('finish', function () { + const blob = stream.toBlob('application/pdf'); + downloadFile(blob, `permissions-changed-${file.name}`); + hideLoader(); + showAlert('Success', 'Permissions changed successfully!'); + }); + + } catch (e) { + console.error(e); + hideLoader(); + showAlert('Error', `An unexpected error occurred: ${e.message}`); + } +} \ No newline at end of file diff --git a/src/js/logic/change-text-color.ts b/src/js/logic/change-text-color.ts new file mode 100644 index 0000000..44dddc3 --- /dev/null +++ b/src/js/logic/change-text-color.ts @@ -0,0 +1,144 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, hexToRgb, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +let isRenderingPreview = false; +let renderTimeout: any; + +async function updateTextColorPreview() { + if (isRenderingPreview) return; + isRenderingPreview = true; + + try { + const textColorCanvas = document.getElementById('text-color-canvas'); + if (!textColorCanvas) return; + + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + const page = await pdf.getPage(1); // Preview first page + const viewport = page.getViewport({ scale: 0.8 }); + // @ts-expect-error TS(2339) FIXME: Property 'getContext' does not exist on type 'HTML... Remove this comment to see the full error message + const context = textColorCanvas.getContext('2d'); + + // @ts-expect-error TS(2339) FIXME: Property 'width' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + textColorCanvas.width = viewport.width; + // @ts-expect-error TS(2339) FIXME: Property 'height' does not exist on type 'HTMLElem... Remove this comment to see the full error message + textColorCanvas.height = viewport.height; + + await page.render({ canvasContext: context, viewport }).promise; + + // @ts-expect-error TS(2339) FIXME: Property 'width' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const imageData = context.getImageData(0, 0, textColorCanvas.width, textColorCanvas.height); + const data = imageData.data; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const colorHex = document.getElementById('text-color-input').value; + const { r, g, b } = hexToRgb(colorHex); + const darknessThreshold = 120; + + for (let i = 0; i < data.length; i += 4) { + if (data[i] < darknessThreshold && data[i + 1] < darknessThreshold && data[i + 2] < darknessThreshold) { + data[i] = r * 255; + data[i + 1] = g * 255; + data[i + 2] = b * 255; + } + } + context.putImageData(imageData, 0, 0); + } catch (error) { + console.error('Error updating preview:', error); + } finally { + isRenderingPreview = false; + } +} + +export async function setupTextColorTool() { + const originalCanvas = document.getElementById('original-canvas'); + const colorInput = document.getElementById('text-color-input'); + + if (!originalCanvas || !colorInput) return; + + // Debounce the preview update for performance + colorInput.addEventListener('input', () => { + clearTimeout(renderTimeout); + renderTimeout = setTimeout(updateTextColorPreview, 250); + }); + + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + const page = await pdf.getPage(1); + const viewport = page.getViewport({ scale: 0.8 }); + + // @ts-expect-error TS(2339) FIXME: Property 'width' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + originalCanvas.width = viewport.width; + // @ts-expect-error TS(2339) FIXME: Property 'height' does not exist on type 'HTMLElem... Remove this comment to see the full error message + originalCanvas.height = viewport.height; + + // @ts-expect-error TS(2339) FIXME: Property 'getContext' does not exist on type 'HTML... Remove this comment to see the full error message + await page.render({ canvasContext: originalCanvas.getContext('2d'), viewport }).promise; + await updateTextColorPreview(); +} + +export async function changeTextColor() { + if (!state.pdfDoc) { + showAlert('Error', 'PDF not loaded.'); + return; + } + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const colorHex = document.getElementById('text-color-input').value; + const { r, g, b } = hexToRgb(colorHex); + const darknessThreshold = 120; + + showLoader('Changing text color...'); + try { + const newPdfDoc = await PDFLibDocument.create(); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + + for (let i = 1; i <= pdf.numPages; i++) { + showLoader(`Processing page ${i} of ${pdf.numPages}...`); + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2.0 }); // High resolution for quality + + const canvas = document.createElement('canvas'); + canvas.width = viewport.width; + canvas.height = viewport.height; + const context = canvas.getContext('2d'); + + await page.render({ canvasContext: context, viewport }).promise; + + const imageData = context.getImageData(0, 0, canvas.width, canvas.height); + const data = imageData.data; + + for (let j = 0; j < data.length; j += 4) { + if (data[j] < darknessThreshold && data[j + 1] < darknessThreshold && data[j + 2] < darknessThreshold) { + data[j] = r * 255; + data[j + 1] = g * 255; + data[j + 2] = b * 255; + } + } + context.putImageData(imageData, 0, 0); + + const pngImageBytes = await new Promise(resolve => canvas.toBlob(blob => { + const reader = new FileReader(); + // @ts-expect-error TS(2769) FIXME: No overload matches this call. + reader.onload = () => resolve(new Uint8Array(reader.result)); + reader.readAsArrayBuffer(blob); + }, 'image/png')); + + const pngImage = await newPdfDoc.embedPng(pngImageBytes as ArrayBuffer); + const newPage = newPdfDoc.addPage([viewport.width, viewport.height]); + newPage.drawImage(pngImage, { x: 0, y: 0, width: viewport.width, height: viewport.height }); + } + + const newPdfBytes = await newPdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'text-color-changed.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not change text color.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/combine-single-page.ts b/src/js/logic/combine-single-page.ts new file mode 100644 index 0000000..6218588 --- /dev/null +++ b/src/js/logic/combine-single-page.ts @@ -0,0 +1,77 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, hexToRgb } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument, rgb } from 'pdf-lib'; + +export async function combineToSinglePage() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const spacing = parseInt(document.getElementById('page-spacing').value) || 0; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const backgroundColorHex = document.getElementById('background-color').value; + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + const addSeparator = document.getElementById('add-separator').checked; + const backgroundColor = hexToRgb(backgroundColorHex); + + showLoader('Combining pages...'); + try { + const sourceDoc = state.pdfDoc; + const newDoc = await PDFLibDocument.create(); + const sourcePages = sourceDoc.getPages(); + + let maxWidth = 0; + let totalHeight = 0; + sourcePages.forEach((page: any) => { + const { width, height } = page.getSize(); + if (width > maxWidth) maxWidth = width; + totalHeight += height; + }); + totalHeight += Math.max(0, sourcePages.length - 1) * spacing; + + const newPage = newDoc.addPage([maxWidth, totalHeight]); + + if (backgroundColorHex.toUpperCase() !== '#FFFFFF') { + newPage.drawRectangle({ + x: 0, + y: 0, + width: maxWidth, + height: totalHeight, + color: rgb(backgroundColor.r, backgroundColor.g, backgroundColor.b), + }); + } + + let currentY = totalHeight; + for (let i = 0; i < sourcePages.length; i++) { + const sourcePage = sourcePages[i]; + const { width, height } = sourcePage.getSize(); + const embeddedPage = await newDoc.embedPage(sourcePage); + + currentY -= height; + const x = (maxWidth - width) / 2; + + newPage.drawPage(embeddedPage, { x, y: currentY, width, height }); + + if (addSeparator && i < sourcePages.length - 1) { + const lineY = currentY - (spacing / 2); + newPage.drawLine({ + start: { x: 0, y: lineY }, + end: { x: maxWidth, y: lineY }, + thickness: 0.5, + color: rgb(0.8, 0.8, 0.8), + }); + } + + currentY -= spacing; + } + + const newPdfBytes = await newDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'combined-page.pdf'); + + } catch (e) { + console.error(e); + showAlert('Error', 'An error occurred while combining pages.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/compare-pdfs.ts b/src/js/logic/compare-pdfs.ts new file mode 100644 index 0000000..d7c1d42 --- /dev/null +++ b/src/js/logic/compare-pdfs.ts @@ -0,0 +1,193 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { readFileAsArrayBuffer } from '../utils/helpers.js'; +import { icons, createIcons } from "lucide"; + +const state = { + pdfDoc1: null, + pdfDoc2: null, + currentPage: 1, + viewMode: 'overlay', + isSyncScroll: true, +}; + +/** + * Renders a PDF page to fit the width of its container. + * @param {PDFDocumentProxy} pdfDoc - The loaded PDF document from pdf.js. + * @param {number} pageNum - The page number to render. + * @param {HTMLCanvasElement} canvas - The canvas element to draw on. + * @param {HTMLElement} container - The container to fit the canvas into. + */ +async function renderPage(pdfDoc: any, pageNum: any, canvas: any, container: any) { + const page = await pdfDoc.getPage(pageNum); + + // Calculate scale to fit the container width. + const containerWidth = container.clientWidth - 2; // Subtract border width + const viewport = page.getViewport({ scale: 1.0 }); + const scale = containerWidth / viewport.width; + const scaledViewport = page.getViewport({ scale: scale }); + + canvas.width = scaledViewport.width; + canvas.height = scaledViewport.height; + + await page.render({ + canvasContext: canvas.getContext('2d'), + viewport: scaledViewport, + }).promise; +} + + +async function renderBothPages() { + if (!state.pdfDoc1 || !state.pdfDoc2) return; + + showLoader(`Loading page ${state.currentPage}...`); + + const canvas1 = document.getElementById('canvas-compare-1'); + const canvas2 = document.getElementById('canvas-compare-2'); + const panel1 = document.getElementById('panel-1'); + const panel2 = document.getElementById('panel-2'); + const wrapper = document.getElementById('compare-viewer-wrapper'); + + // Determine the correct container based on the view mode + const container1 = state.viewMode === 'overlay' ? wrapper : panel1; + const container2 = state.viewMode === 'overlay' ? wrapper : panel2; + + await Promise.all([ + renderPage(state.pdfDoc1, Math.min(state.currentPage, state.pdfDoc1.numPages), canvas1, container1), + renderPage(state.pdfDoc2, Math.min(state.currentPage, state.pdfDoc2.numPages), canvas2, container2) + ]); + + updateNavControls(); + hideLoader(); +} + +function updateNavControls() { + const maxPages = Math.max(state.pdfDoc1?.numPages || 0, state.pdfDoc2?.numPages || 0); + // @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'. + document.getElementById('current-page-display-compare').textContent = state.currentPage; + // @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'. + document.getElementById('total-pages-display-compare').textContent = maxPages; + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + document.getElementById('prev-page-compare').disabled = state.currentPage <= 1; + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + document.getElementById('next-page-compare').disabled = state.currentPage >= maxPages; +} + +async function setupFileInput(inputId: any, docKey: any, displayId: any) { + const fileInput = document.getElementById(inputId); + const dropZone = document.getElementById(`drop-zone-${inputId.slice(-1)}`); + + const handleFile = async (file: any) => { + if (!file || file.type !== 'application/pdf') return showAlert('Invalid File', 'Please select a valid PDF file.'); + + const displayDiv = document.getElementById(displayId); + displayDiv.innerHTML = `

${file.name}

`; + createIcons({icons}); + + try { + showLoader(`Loading ${file.name}...`); + const pdfBytes = await readFileAsArrayBuffer(file); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + state[docKey] = await pdfjsLib.getDocument(pdfBytes).promise; + + if (state.pdfDoc1 && state.pdfDoc2) { + document.getElementById('compare-viewer').classList.remove('hidden'); + state.currentPage = 1; + await renderBothPages(); + } + } catch (e) { + showAlert('Error', 'Could not load PDF. It may be corrupt or password-protected.'); + console.error(e); + } finally { + hideLoader(); + } + }; + + // @ts-expect-error TS(2339) FIXME: Property 'files' does not exist on type 'EventTarg... Remove this comment to see the full error message + fileInput.addEventListener('change', (e) => handleFile(e.target.files[0])); + dropZone.addEventListener('dragover', (e) => e.preventDefault()); + dropZone.addEventListener('drop', (e) => { e.preventDefault(); handleFile(e.dataTransfer.files[0]); }); +} + +/** + * Toggles the UI between Overlay and Side-by-Side views. + * @param {'overlay' | 'side-by-side'} mode + */ +function setViewMode(mode: any) { + state.viewMode = mode; + const wrapper = document.getElementById('compare-viewer-wrapper'); + const overlayControls = document.getElementById('overlay-controls'); + const sideControls = document.getElementById('side-by-side-controls'); + const btnOverlay = document.getElementById('view-mode-overlay'); + const btnSide = document.getElementById('view-mode-side'); + const canvas2 = document.getElementById('canvas-compare-2'); + const opacitySlider = document.getElementById('opacity-slider'); + + + if (mode === 'overlay') { + wrapper.className = 'compare-viewer-wrapper overlay-mode'; + overlayControls.classList.remove('hidden'); + sideControls.classList.add('hidden'); + btnOverlay.classList.add('bg-indigo-600'); + btnSide.classList.remove('bg-indigo-600'); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + canvas2.style.opacity = opacitySlider.value; + } else { + wrapper.className = 'compare-viewer-wrapper side-by-side-mode'; + overlayControls.classList.add('hidden'); + sideControls.classList.remove('hidden'); + btnOverlay.classList.remove('bg-indigo-600'); + btnSide.classList.add('bg-indigo-600'); + // CHANGE: When switching to side-by-side, reset the canvas opacity to 1. + canvas2.style.opacity = '1'; + } + renderBothPages(); +} + +export function setupCompareTool() { + setupFileInput('file-input-1', 'pdfDoc1', 'file-display-1'); + setupFileInput('file-input-2', 'pdfDoc2', 'file-display-2'); + + document.getElementById('prev-page-compare').addEventListener('click', () => { + if (state.currentPage > 1) { state.currentPage--; renderBothPages(); } + }); + document.getElementById('next-page-compare').addEventListener('click', () => { + const maxPages = Math.max(state.pdfDoc1.numPages, state.pdfDoc2.numPages); + if (state.currentPage < maxPages) { state.currentPage++; renderBothPages(); } + }); + + document.getElementById('view-mode-overlay').addEventListener('click', () => setViewMode('overlay')); + document.getElementById('view-mode-side').addEventListener('click', () => setViewMode('side-by-side')); + + const canvas2 = document.getElementById('canvas-compare-2'); + document.getElementById('flicker-btn').addEventListener('click', () => { + canvas2.style.transition = 'opacity 150ms ease-in-out'; + canvas2.style.opacity = (canvas2.style.opacity === '0') ? '1' : '0'; + }); + document.getElementById('opacity-slider').addEventListener('input', (e) => { + canvas2.style.transition = ''; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'EventTarg... Remove this comment to see the full error message + canvas2.style.opacity = e.target.value; + }); + + const panel1 = document.getElementById('panel-1'); + const panel2 = document.getElementById('panel-2'); + const syncToggle = document.getElementById('sync-scroll-toggle'); + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + syncToggle.addEventListener('change', () => { state.isSyncScroll = syncToggle.checked; }); + + let scrollingPanel: any = null; + panel1.addEventListener('scroll', () => { + if (state.isSyncScroll && scrollingPanel !== panel2) { + scrollingPanel = panel1; + panel2.scrollTop = panel1.scrollTop; + setTimeout(() => scrollingPanel = null, 100); + } + }); + panel2.addEventListener('scroll', () => { + if (state.isSyncScroll && scrollingPanel !== panel1) { + scrollingPanel = panel2; + panel1.scrollTop = panel2.scrollTop; + setTimeout(() => scrollingPanel = null, 100); + } + }); +} \ No newline at end of file diff --git a/src/js/logic/compress.ts b/src/js/logic/compress.ts new file mode 100644 index 0000000..a975e50 --- /dev/null +++ b/src/js/logic/compress.ts @@ -0,0 +1,279 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer, formatBytes } from '../utils/helpers.js'; +import { state } from '../state.js'; +import * as pdfjsLib from 'pdfjs-dist'; + + +import { PDFDocument, PDFName, PDFDict, PDFStream, PDFNumber } from 'pdf-lib'; + +function dataUrlToBytes(dataUrl: any) { + const base64 = dataUrl.split(',')[1]; + const binaryString = atob(base64); + const len = binaryString.length; + const bytes = new Uint8Array(len); + for (let i = 0; i < len; i++) { + bytes[i] = binaryString.charCodeAt(i); + } + return bytes; +} + +async function performSmartCompression(arrayBuffer: any, settings: any) { + const pdfDoc = await PDFDocument.load(arrayBuffer, { ignoreEncryption: true }); + const pages = pdfDoc.getPages(); + + if (settings.removeMetadata) { + try { + pdfDoc.setTitle(''); + pdfDoc.setAuthor(''); + pdfDoc.setSubject(''); + pdfDoc.setKeywords([]); + pdfDoc.setCreator(''); + pdfDoc.setProducer(''); + } catch (e) { + console.warn('Could not remove metadata:', e); + } + } + + for (let i = 0; i < pages.length; i++) { + const page = pages[i]; + const resources = page.node.Resources(); + if (!resources) continue; + + const xobjects = resources.lookup(PDFName.of('XObject')); + if (!(xobjects instanceof PDFDict)) continue; + + for (const [key, value] of xobjects.entries()) { + const stream = pdfDoc.context.lookup(value); + if (!(stream instanceof PDFStream) || stream.dict.get(PDFName.of('Subtype')) !== PDFName.of('Image')) continue; + + try { + const imageBytes = stream.getContents(); + if (imageBytes.length < settings.skipSize) continue; + + const width = stream.dict.get(PDFName.of('Width')) instanceof PDFNumber + ? (stream.dict.get(PDFName.of('Width')) as PDFNumber).asNumber() + : 0; + const height = stream.dict.get(PDFName.of('Height')) instanceof PDFNumber + ? (stream.dict.get(PDFName.of('Height')) as PDFNumber).asNumber() + : 0; + const bitsPerComponent = stream.dict.get(PDFName.of('BitsPerComponent')) instanceof PDFNumber + ? (stream.dict.get(PDFName.of('BitsPerComponent')) as PDFNumber).asNumber() + : 8; + + if (width > 0 && height > 0) { + let newWidth = width; + let newHeight = height; + + const scaleFactor = settings.scaleFactor || 1.0; + newWidth = Math.floor(width * scaleFactor); + newHeight = Math.floor(height * scaleFactor); + + if (newWidth > settings.maxWidth || newHeight > settings.maxHeight) { + const aspectRatio = newWidth / newHeight; + if (newWidth > newHeight) { + newWidth = Math.min(newWidth, settings.maxWidth); + newHeight = newWidth / aspectRatio; + } else { + newHeight = Math.min(newHeight, settings.maxHeight); + newWidth = newHeight * aspectRatio; + } + } + + const minDim = settings.minDimension || 50; + if (newWidth < minDim || newHeight < minDim) continue; + + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + canvas.width = Math.floor(newWidth); + canvas.height = Math.floor(newHeight); + + const img = new Image(); + const imageUrl = URL.createObjectURL(new Blob([imageBytes])); + + await new Promise((resolve, reject) => { + img.onload = resolve; + img.onerror = reject; + img.src = imageUrl; + }); + + ctx.imageSmoothingEnabled = settings.smoothing !== false; + ctx.imageSmoothingQuality = settings.smoothingQuality || 'medium'; + + if (settings.grayscale) { + ctx.filter = 'grayscale(100%)'; + } else if (settings.contrast) { + ctx.filter = `contrast(${settings.contrast}) brightness(${settings.brightness || 1})`; + } + + ctx.drawImage(img, 0, 0, canvas.width, canvas.height); + + let bestBytes = null; + let bestSize = imageBytes.length; + + const jpegDataUrl = canvas.toDataURL('image/jpeg', settings.quality); + const jpegBytes = dataUrlToBytes(jpegDataUrl); + if (jpegBytes.length < bestSize) { + bestBytes = jpegBytes; + bestSize = jpegBytes.length; + } + + if (settings.tryWebP) { + try { + const webpDataUrl = canvas.toDataURL('image/webp', settings.quality); + const webpBytes = dataUrlToBytes(webpDataUrl); + if (webpBytes.length < bestSize) { + bestBytes = webpBytes; + bestSize = webpBytes.length; + } + } catch (e) { /* WebP not supported */ } + } + + if (bestBytes && bestSize < imageBytes.length * settings.threshold) { + (stream as any).contents = bestBytes; + stream.dict.set(PDFName.of('Length'), PDFNumber.of(bestSize)); + stream.dict.set(PDFName.of('Width'), PDFNumber.of(canvas.width)); + stream.dict.set(PDFName.of('Height'), PDFNumber.of(canvas.height)); + stream.dict.set(PDFName.of('Filter'), PDFName.of('DCTDecode')); + stream.dict.delete(PDFName.of('DecodeParms')); + stream.dict.set(PDFName.of('BitsPerComponent'), PDFNumber.of(8)); + + if (settings.grayscale) { + stream.dict.set(PDFName.of('ColorSpace'), PDFName.of('DeviceGray')); + } + } + URL.revokeObjectURL(imageUrl); + } + } catch (error) { + console.warn('Skipping an uncompressible image in smart mode:', error); + } + } + } + + const saveOptions = { + useObjectStreams: settings.useObjectStreams !== false, + addDefaultPage: false, + objectsPerTick: settings.objectsPerTick || 50 + }; + + return await pdfDoc.save(saveOptions); +} + +async function performLegacyCompression(arrayBuffer: any, settings: any) { + pdfjsLib.GlobalWorkerOptions.workerSrc = new URL( + 'pdfjs-dist/build/pdf.worker.min.mjs', + import.meta.url + ).toString(); + + const pdfJsDoc = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; + const newPdfDoc = await PDFDocument.create(); + + for (let i = 1; i <= pdfJsDoc.numPages; i++) { + const page = await pdfJsDoc.getPage(i); + const viewport = page.getViewport({ scale: settings.scale }); + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.height = viewport.height; + canvas.width = viewport.width; + + await page.render({ canvasContext: context, viewport, canvas: canvas }).promise; + + const jpegBlob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', settings.quality)); + // @ts-expect-error TS(2339) FIXME: Property 'arrayBuffer' does not exist on type 'unk... Remove this comment to see the full error message + const jpegBytes = await jpegBlob.arrayBuffer(); + const jpegImage = await newPdfDoc.embedJpg(jpegBytes); + const newPage = newPdfDoc.addPage([viewport.width, viewport.height]); + newPage.drawImage(jpegImage, { x: 0, y: 0, width: viewport.width, height: viewport.height }); + } + return await newPdfDoc.save(); +} + +export async function compress() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const level = document.getElementById('compression-level').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const algorithm = document.getElementById('compression-algorithm').value; + + const settings = { + 'balanced': { + smart: { quality: 0.5, threshold: 0.95, maxWidth: 1800, maxHeight: 1800, skipSize: 3000 }, + legacy: { scale: 1.5, quality: 0.6 } + }, + 'high-quality': { + smart: { quality: 0.70, threshold: 0.98, maxWidth: 2500, maxHeight: 2500, skipSize: 5000 }, + legacy: { scale: 2.0, quality: 0.9 } + }, + 'small-size': { + smart: { quality: 0.3, threshold: 0.95, maxWidth: 1200, maxHeight: 1200, skipSize: 2000 }, + legacy: { scale: 1.2, quality: 0.4 } + }, + 'extreme': { + smart: { quality: 0.1, threshold: 0.95, maxWidth: 1000, maxHeight: 1000, skipSize: 1000 }, + legacy: { scale: 1.0, quality: 0.2 } + } + }; + + const smartSettings = { ...settings[level].smart, removeMetadata: true }; + const legacySettings = settings[level].legacy; + + try { + const originalFile = state.files[0]; + const arrayBuffer = await readFileAsArrayBuffer(originalFile); + + let resultBytes; + let usedMethod; + + if (algorithm === 'vector') { + showLoader('Running Vector (Smart) compression...'); + resultBytes = await performSmartCompression(arrayBuffer, smartSettings); + usedMethod = 'Vector'; + } else if (algorithm === 'photon') { + showLoader('Running Photon (Rasterize) compression...'); + resultBytes = await performLegacyCompression(arrayBuffer, legacySettings); + usedMethod = 'Photon'; + } else { + showLoader('Running Automatic (Vector first)...'); + const vectorResultBytes = await performSmartCompression(arrayBuffer, smartSettings); + + if (vectorResultBytes.length < originalFile.size) { + resultBytes = vectorResultBytes; + usedMethod = 'Vector (Automatic)'; + } else { + // @ts-expect-error TS(2554) FIXME: Expected 2 arguments, but got 3. + showAlert('Vector failed to reduce size. Trying Photon...', 'info', 3000); + showLoader('Running Automatic (Photon fallback)...'); + resultBytes = await performLegacyCompression(arrayBuffer, legacySettings); + usedMethod = 'Photon (Automatic)'; + } + } + + const originalSize = formatBytes(originalFile.size); + const compressedSize = formatBytes(resultBytes.length); + const savings = originalFile.size - resultBytes.length; + const savingsPercent = savings > 0 ? ((savings / originalFile.size) * 100).toFixed(1) : 0; + + if (savings > 0) { + showAlert( + 'Compression Complete', + `Method: **${usedMethod}**. ` + + `File size reduced from ${originalSize} to ${compressedSize} (Saved ${savingsPercent}%).` + ); + } else { + showAlert( + 'Compression Finished', + `Method: **${usedMethod}**. ` + + `Could not reduce file size. Original: ${originalSize}, New: ${compressedSize}.`, + // @ts-expect-error TS(2554) FIXME: Expected 2 arguments, but got 3. + 'warning' + ); + } + + downloadFile(new Blob([resultBytes], { type: 'application/pdf' }), 'compressed-final.pdf'); + + } catch (e) { + console.error(e); + // @ts-expect-error TS(2554) FIXME: Expected 2 arguments, but got 3. + showAlert('Error', `An error occurred during compression. Error: ${e.message}`, 'error'); + } finally { + hideLoader(); + } +} diff --git a/src/js/logic/cropper.ts b/src/js/logic/cropper.ts new file mode 100644 index 0000000..43c4f4f --- /dev/null +++ b/src/js/logic/cropper.ts @@ -0,0 +1,320 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import Cropper from "cropperjs"; +import * as pdfjsLib from 'pdfjs-dist'; +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + + +// --- Global State for the Cropper Tool --- +const cropperState = { + pdfDoc: null, + currentPageNum: 1, + cropper: null, + originalPdfBytes: null, + cropperImageElement: null, + pageCrops: {}, +}; + +/** + * Saves the current crop data to the state object. + */ +function saveCurrentCrop() { + if (cropperState.cropper) { + const currentCrop = cropperState.cropper.getData(true); + const imageData = cropperState.cropper.getImageData(); + const cropPercentages = { + x: currentCrop.x / imageData.naturalWidth, + y: currentCrop.y / imageData.naturalHeight, + width: currentCrop.width / imageData.naturalWidth, + height: currentCrop.height / imageData.naturalHeight, + }; + cropperState.pageCrops[cropperState.currentPageNum] = cropPercentages; + } +} + +/** + * Renders a PDF page to the Cropper UI as an image. + * @param {number} num The page number to render. + */ +async function displayPageAsImage(num: any) { + showLoader(`Rendering Page ${num}...`); + + try { + const page = await cropperState.pdfDoc.getPage(num); + const viewport = page.getViewport({ scale: 2.5 }); + + const tempCanvas = document.createElement('canvas'); + const tempCtx = tempCanvas.getContext('2d'); + tempCanvas.width = viewport.width; + tempCanvas.height = viewport.height; + await page.render({ canvasContext: tempCtx, viewport: viewport }).promise; + + if (cropperState.cropper) { + cropperState.cropper.destroy(); + } + + const image = document.createElement('img'); + image.src = tempCanvas.toDataURL('image/png'); + document.getElementById('cropper-container').innerHTML = ''; + document.getElementById('cropper-container').appendChild(image); + + image.onload = () => { + cropperState.cropper = new Cropper(image, { + viewMode: 1, + background: false, + autoCropArea: 0.8, + responsive: true, + rotatable: false, + zoomable: false, + }); + + // Restore saved crop data for this page + const savedCrop = cropperState.pageCrops[num]; + if (savedCrop) { + const imageData = cropperState.cropper.getImageData(); + const cropData = { + x: savedCrop.x * imageData.naturalWidth, + y: savedCrop.y * imageData.naturalHeight, + width: savedCrop.width * imageData.naturalWidth, + height: savedCrop.height * imageData.naturalHeight, + }; + cropperState.cropper.setData(cropData); + } + + updatePageInfo(); + enableControls(); + hideLoader(); + showAlert('Ready', 'Please select an area to crop.'); + }; + } catch (error) { + console.error("Error rendering page:", error); + showAlert('Error', 'Failed to render page.'); + hideLoader(); + } +} + +/** + * Handles page navigation. + * @param {number} offset -1 for previous, 1 for next. + */ +async function changePage(offset: any) { + // Save the current page's crop before changing + saveCurrentCrop(); + + const newPageNum = cropperState.currentPageNum + offset; + if (newPageNum > 0 && newPageNum <= cropperState.pdfDoc.numPages) { + cropperState.currentPageNum = newPageNum; + await displayPageAsImage(cropperState.currentPageNum); + } +} + +function updatePageInfo() { + document.getElementById('page-info').textContent = `Page ${cropperState.currentPageNum} of ${cropperState.pdfDoc.numPages}`; +} + +function enableControls() { + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + document.getElementById('prev-page').disabled = cropperState.currentPageNum <= 1; + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + document.getElementById('next-page').disabled = cropperState.currentPageNum >= cropperState.pdfDoc.numPages; + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + document.getElementById('crop-button').disabled = false; +} + +/** + * Performs a non-destructive crop by updating the page's crop box. + */ +async function performMetadataCrop(pdfToModify: any, cropData: any) { + for (const pageNum in cropData) { + // @ts-expect-error TS(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message + const page = pdfToModify.getPages()[pageNum - 1]; + const { width: pageWidth, height: pageHeight } = page.getSize(); + const rotation = page.getRotation().angle; + const crop = cropData[pageNum]; + + const visualPdfWidth = pageWidth * crop.width; + const visualPdfHeight = pageHeight * crop.height; + const visualPdfX = pageWidth * crop.x; + const visualPdfY = pageHeight * crop.y; + + let finalX, finalY, finalWidth, finalHeight; + switch (rotation) { + case 90: + finalX = visualPdfY; + finalY = pageWidth - visualPdfX - visualPdfWidth; + finalWidth = visualPdfHeight; + finalHeight = visualPdfWidth; + break; + case 180: + finalX = pageWidth - visualPdfX - visualPdfWidth; + finalY = pageHeight - visualPdfY - visualPdfHeight; + finalWidth = visualPdfWidth; + finalHeight = visualPdfHeight; + break; + case 270: + finalX = pageHeight - visualPdfY - visualPdfHeight; + finalY = visualPdfX; + finalWidth = visualPdfHeight; + finalHeight = visualPdfWidth; + break; + default: + finalX = visualPdfX; + finalY = pageHeight - visualPdfY - visualPdfHeight; + finalWidth = visualPdfWidth; + finalHeight = visualPdfHeight; + break; + } + page.setCropBox(finalX, finalY, finalWidth, finalHeight); + } +} + +// FILE: js/logic/cropper.js + +/** + * Performs a destructive crop by flattening the selected area to an image. + */ +async function performFlatteningCrop(cropData: any) { + const newPdfDoc = await PDFLibDocument.create(); + + // Load the original PDF with pdf-lib to copy un-cropped pages from + const sourcePdfDocForCopying = await PDFLibDocument.load(cropperState.originalPdfBytes); + + // CORRECTED: Use .numPages from the pdf.js document object + const totalPages = cropperState.pdfDoc.numPages; + + for (let i = 0; i < totalPages; i++) { + const pageNum = i + 1; + showLoader(`Processing page ${pageNum} of ${totalPages}...`); + + if (cropData[pageNum]) { + const page = await cropperState.pdfDoc.getPage(pageNum); + const viewport = page.getViewport({ scale: 2.5 }); + + const tempCanvas = document.createElement('canvas'); + const tempCtx = tempCanvas.getContext('2d'); + tempCanvas.width = viewport.width; + tempCanvas.height = viewport.height; + await page.render({ canvasContext: tempCtx, viewport: viewport }).promise; + + const finalCanvas = document.createElement('canvas'); + const finalCtx = finalCanvas.getContext('2d'); + const crop = cropData[pageNum]; + const finalWidth = tempCanvas.width * crop.width; + const finalHeight = tempCanvas.height * crop.height; + finalCanvas.width = finalWidth; + finalCanvas.height = finalHeight; + + finalCtx.drawImage( + tempCanvas, + tempCanvas.width * crop.x, tempCanvas.height * crop.y, + finalWidth, finalHeight, + 0, 0, finalWidth, finalHeight + ); + + const pngBytes = await new Promise(res => finalCanvas.toBlob(blob => blob.arrayBuffer().then(res), 'image/png')); + const embeddedImage = await newPdfDoc.embedPng(pngBytes as ArrayBuffer); + const newPage = newPdfDoc.addPage([finalWidth, finalHeight]); + newPage.drawImage(embeddedImage, { x: 0, y: 0, width: finalWidth, height: finalHeight }); + } else { + // Correctly copy the page from the source pdf-lib document + const [copiedPage] = await newPdfDoc.copyPages(sourcePdfDocForCopying, [i]); + newPdfDoc.addPage(copiedPage); + } + } + return newPdfDoc; +} + +/** + * Main function to set up the Cropper tool. + */ +export async function setupCropperTool() { + if (state.files.length === 0) return; + + // Clear pageCrops on new file upload + cropperState.pageCrops = {}; + + const arrayBuffer = await readFileAsArrayBuffer(state.files[0]); + cropperState.originalPdfBytes = arrayBuffer; + const arrayBufferForPdfJs = (arrayBuffer as ArrayBuffer).slice(0); + + + // pdfjsLib.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js`; + pdfjsLib.GlobalWorkerOptions.workerSrc = new URL( + 'pdfjs-dist/build/pdf.worker.min.mjs', + import.meta.url + ).toString(); + + try { + // const loadingTask = pdfjsLib.getDocument({ data: cropperState.originalPdfBytes }); + const loadingTask = pdfjsLib.getDocument({ data: arrayBufferForPdfJs }); + + cropperState.pdfDoc = await loadingTask.promise; + cropperState.currentPageNum = 1; + + await displayPageAsImage(cropperState.currentPageNum); + + document.getElementById('prev-page').addEventListener('click', () => changePage(-1)); + document.getElementById('next-page').addEventListener('click', () => changePage(1)); + + document.getElementById('crop-button').addEventListener('click', async () => { + // Get the last known crop from the active page before processing + saveCurrentCrop(); + + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + const isDestructive = document.getElementById('destructive-crop-toggle').checked; + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + const isApplyToAll = document.getElementById('apply-to-all-toggle').checked; + + let finalCropData = {}; + if (isApplyToAll) { + const currentCrop = cropperState.pageCrops[cropperState.currentPageNum]; + if (!currentCrop) { + showAlert('No Crop Area', 'Please select an area to crop first.'); + return; + } + // Apply the active page's crop to all pages + for (let i = 1; i <= cropperState.pdfDoc.numPages; i++) { + finalCropData[i] = currentCrop; + } + } else { + // If not applying to all, only process pages with saved crops + finalCropData = Object.keys(cropperState.pageCrops).reduce((obj, key) => { + obj[key] = cropperState.pageCrops[key]; + return obj; + }, {}); + } + + if (Object.keys(finalCropData).length === 0) { + showAlert('No Crop Area', 'Please select an area on at least one page to crop.'); + return; + } + + showLoader('Applying crop...'); + + try { + let finalPdfBytes; + if (isDestructive) { + const newPdfDoc = await performFlatteningCrop(finalCropData); + finalPdfBytes = await newPdfDoc.save(); + } else { + const pdfToModify = await PDFLibDocument.load(cropperState.originalPdfBytes); + await performMetadataCrop(pdfToModify, finalCropData); + finalPdfBytes = await pdfToModify.save(); + } + + const fileName = isDestructive ? 'flattened_crop.pdf' : 'standard_crop.pdf'; + downloadFile(new Blob([finalPdfBytes], { type: 'application/pdf' }), fileName); + showAlert('Success', 'Crop complete! Your download has started.'); + } catch (e) { + console.error(e); + showAlert('Error', 'An error occurred during cropping.'); + } finally { + hideLoader(); + } + }); + } catch (error) { + console.error("Error setting up cropper tool:", error); + showAlert('Error', 'Failed to load PDF for cropping.'); + } +} diff --git a/src/js/logic/decrypt.ts b/src/js/logic/decrypt.ts new file mode 100644 index 0000000..0d1cc11 --- /dev/null +++ b/src/js/logic/decrypt.ts @@ -0,0 +1,65 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import PDFDocument from 'pdfkit/js/pdfkit.standalone'; +import blobStream from 'blob-stream'; +import * as pdfjsLib from "pdfjs-dist"; + +export async function decrypt() { + const file = state.files[0]; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const password = document.getElementById('password-input').value; + if (!password.trim()) { + showAlert('Input Required', 'Please enter the PDF password.'); + return; + } + + try { + showLoader('Preparing to process...'); + const pdfData = await readFileAsArrayBuffer(file); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument({ data: pdfData, password: password }).promise; + const numPages = pdf.numPages; + const pageImages = []; + + for (let i = 1; i <= numPages; i++) { + document.getElementById('loader-text').textContent = `Processing page ${i} of ${numPages}...`; + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2.0 }); + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.height = viewport.height; + canvas.width = viewport.width; + await page.render({ canvasContext: context, viewport: viewport, canvas: canvas }).promise; + pageImages.push({ + data: canvas.toDataURL('image/jpeg', 0.8), + width: viewport.width, + height: viewport.height + }); + } + + document.getElementById('loader-text').textContent = 'Building unlocked PDF...'; + const doc = new PDFDocument({ size: [pageImages[0].width, pageImages[0].height] }); + const stream = doc.pipe(blobStream()); + for (let i = 0; i < pageImages.length; i++) { + if (i > 0) doc.addPage({ size: [pageImages[i].width, pageImages[i].height] }); + doc.image(pageImages[i].data, 0, 0, { width: pageImages[i].width, height: pageImages[i].height }); + } + doc.end(); + + stream.on('finish', function () { + const blob = stream.toBlob('application/pdf'); + downloadFile(blob, `unlocked-${file.name}`); + hideLoader(); + showAlert('Success', 'Decryption complete! Your download has started.'); + }); + } catch (error) { + console.error("Error during PDF decryption:", error); + hideLoader(); + if (error.name === 'PasswordException') { + showAlert('Incorrect Password', 'The password you entered is incorrect.'); + } else { + showAlert('Error', 'An error occurred. The PDF might be corrupted.'); + } + } +} \ No newline at end of file diff --git a/src/js/logic/delete-pages.ts b/src/js/logic/delete-pages.ts new file mode 100644 index 0000000..0ccf115 --- /dev/null +++ b/src/js/logic/delete-pages.ts @@ -0,0 +1,57 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function deletePages() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const pageInput = document.getElementById('pages-to-delete').value; + if (!pageInput) { + showAlert('Invalid Input', 'Please enter page numbers to delete.'); + return; + } + showLoader('Deleting pages...'); + try { + const totalPages = state.pdfDoc.getPageCount(); + const indicesToDelete = new Set(); + const ranges = pageInput.split(','); + + for (const range of ranges) { + const trimmedRange = range.trim(); + if (trimmedRange.includes('-')) { + const [start, end] = trimmedRange.split('-').map(Number); + if (isNaN(start) || isNaN(end) || start < 1 || end > totalPages || start > end) continue; + for (let i = start; i <= end; i++) indicesToDelete.add(i - 1); + } else { + const pageNum = Number(trimmedRange); + if (isNaN(pageNum) || pageNum < 1 || pageNum > totalPages) continue; + indicesToDelete.add(pageNum - 1); + } + } + + if (indicesToDelete.size === 0) { + showAlert('Invalid Input', 'No valid pages selected for deletion.'); + hideLoader(); + return; + } + if (indicesToDelete.size >= totalPages) { + showAlert('Invalid Input', 'You cannot delete all pages.'); + hideLoader(); + return; + } + + const indicesToKeep = Array.from({ length: totalPages }, (_, i) => i).filter(index => !indicesToDelete.has(index)); + const newPdf = await PDFLibDocument.create(); + const copiedPages = await newPdf.copyPages(state.pdfDoc, indicesToKeep); + copiedPages.forEach((page: any) => newPdf.addPage(page)); + + const newPdfBytes = await newPdf.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'deleted-pages.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not delete pages.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/duplicate-organize.ts b/src/js/logic/duplicate-organize.ts new file mode 100644 index 0000000..1a189d6 --- /dev/null +++ b/src/js/logic/duplicate-organize.ts @@ -0,0 +1,145 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import Sortable from 'sortablejs' +import {icons, createIcons} from "lucide"; +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +const duplicateOrganizeState = { + sortableInstances: {} +}; + +function initializePageGridSortable() { + const grid = document.getElementById('page-grid'); + if (!grid) return; + + // @ts-expect-error TS(2339) FIXME: Property 'pageGrid' does not exist on type '{}'. + if (duplicateOrganizeState.sortableInstances.pageGrid) { + // @ts-expect-error TS(2339) FIXME: Property 'pageGrid' does not exist on type '{}'. + duplicateOrganizeState.sortableInstances.pageGrid.destroy(); + } + + // @ts-expect-error TS(2339) FIXME: Property 'pageGrid' does not exist on type '{}'. + duplicateOrganizeState.sortableInstances.pageGrid = Sortable.create(grid, { + animation: 150, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + filter: '.duplicate-btn, .delete-btn', + preventOnFilter: true, + onStart: function(evt: any) { + evt.item.style.opacity = '0.5'; + }, + onEnd: function(evt: any) { + evt.item.style.opacity = '1'; + } + }); +} + +/** + * Attaches event listeners for duplicate and delete to a page thumbnail element. + * @param {HTMLElement} element The thumbnail element to attach listeners to. + */ +function attachEventListeners(element: any) { + // Re-number all visible page labels + const renumberPages = () => { + const grid = document.getElementById('page-grid'); + const pages = grid.querySelectorAll('.page-number'); + pages.forEach((label, index) => { + // @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'. + label.textContent = index + 1; + }); + }; + + // Duplicate button listener + element.querySelector('.duplicate-btn').addEventListener('click', (e: any) => { + e.stopPropagation(); + const clone = element.cloneNode(true); + element.after(clone); + attachEventListeners(clone); + renumberPages(); + initializePageGridSortable(); + }); + + element.querySelector('.delete-btn').addEventListener('click', (e: any) => { + e.stopPropagation(); + if (document.getElementById('page-grid').children.length > 1) { + element.remove(); + renumberPages(); + initializePageGridSortable(); + } else { + showAlert('Cannot Delete', 'You cannot delete the last page of the document.'); + } + }); +} + +export async function renderDuplicateOrganizeThumbnails() { + const grid = document.getElementById('page-grid'); + if (!grid) return; + + showLoader('Rendering page previews...'); + const pdfData = await state.pdfDoc.save(); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdfjsDoc = await pdfjsLib.getDocument({ data: pdfData }).promise; + + grid.innerHTML = ''; + + for (let i = 1; i <= pdfjsDoc.numPages; i++) { + const page = await pdfjsDoc.getPage(i); + const viewport = page.getViewport({ scale: 0.5 }); + const canvas = document.createElement('canvas'); + canvas.height = viewport.height; + canvas.width = viewport.width; + await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise; + + const wrapper = document.createElement('div'); + wrapper.className = 'page-thumbnail relative cursor-move flex flex-col items-center gap-2'; + // @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'. + wrapper.dataset.originalPageIndex = i - 1; + + wrapper.innerHTML = ` +
+ +
+ ${i} +
+ + +
+`; + grid.appendChild(wrapper); + attachEventListeners(wrapper); + } + + initializePageGridSortable(); + createIcons({icons}); + hideLoader(); +} + + +export async function processAndSave() { + showLoader('Building new PDF...'); + try { + const grid = document.getElementById('page-grid'); + const finalPageElements = grid.querySelectorAll('.page-thumbnail'); + + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + const finalIndices = Array.from(finalPageElements).map(el => parseInt(el.dataset.originalPageIndex)); + + const newPdfDoc = await PDFLibDocument.create(); + const copiedPages = await newPdfDoc.copyPages(state.pdfDoc, finalIndices); + copiedPages.forEach((page: any) => newPdfDoc.addPage(page)); + + const newPdfBytes = await newPdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'organized.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to save the new PDF.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/edit-metadata.ts b/src/js/logic/edit-metadata.ts new file mode 100644 index 0000000..b9ab201 --- /dev/null +++ b/src/js/logic/edit-metadata.ts @@ -0,0 +1,73 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import { PDFName, PDFString } from "pdf-lib" + + +export async function editMetadata() { + showLoader('Updating metadata...'); + try { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + state.pdfDoc.setTitle(document.getElementById('meta-title').value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + state.pdfDoc.setAuthor(document.getElementById('meta-author').value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + state.pdfDoc.setSubject(document.getElementById('meta-subject').value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + state.pdfDoc.setCreator(document.getElementById('meta-creator').value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + state.pdfDoc.setProducer(document.getElementById('meta-producer').value); + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const keywords = document.getElementById('meta-keywords').value; + state.pdfDoc.setKeywords(keywords.split(',').map((k: any) => k.trim()).filter(Boolean)); + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const creationDate = document.getElementById('meta-creation-date').value; + if (creationDate) { + state.pdfDoc.setCreationDate(new Date(creationDate)); + } + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const modDate = document.getElementById('meta-mod-date').value; + if (modDate) { + state.pdfDoc.setModificationDate(new Date(modDate)); + } else { + state.pdfDoc.setModificationDate(new Date()); + } + + const infoDict = state.pdfDoc.getInfoDict(); + const standardKeys = new Set(['Title', 'Author', 'Subject', 'Keywords', 'Creator', 'Producer', 'CreationDate', 'ModDate']); + + const allKeys = infoDict.keys().map((key: any) => key.asString().substring(1)); // Clean keys + + allKeys.forEach((key: any) => { + if (!standardKeys.has(key)) { + infoDict.delete(PDFName.of(key)); + } + }); + + const customKeys = document.querySelectorAll('.custom-meta-key'); + const customValues = document.querySelectorAll('.custom-meta-value'); + + customKeys.forEach((keyInput, index) => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + const key = keyInput.value.trim(); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + const value = customValues[index].value.trim(); + if (key && value) { + // Now we add the fields to a clean slate + infoDict.set(PDFName.of(key), PDFString.of(value)); + } + }); + + const newPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'metadata-edited.pdf'); + + } catch (e) { + console.error(e); + showAlert('Error', 'Could not update metadata. Please check that date formats are correct.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/encrypt.ts b/src/js/logic/encrypt.ts new file mode 100644 index 0000000..8be5b14 --- /dev/null +++ b/src/js/logic/encrypt.ts @@ -0,0 +1,73 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import PDFDocument from 'pdfkit/js/pdfkit.standalone'; +import blobStream from 'blob-stream'; +import * as pdfjsLib from "pdfjs-dist"; + +export async function encrypt() { + const file = state.files[0]; + const password = (document.getElementById('password-input') as HTMLInputElement).value; + if (!password.trim()) { + showAlert('Input Required', 'Please enter a password.'); + return; + } + + try { + showLoader('Preparing to process...'); + const pdfData = await readFileAsArrayBuffer(file); + const pdf = await pdfjsLib.getDocument({ data: pdfData as ArrayBuffer }).promise; + const numPages = pdf.numPages; + const pageImages = []; + + for (let i = 1; i <= numPages; i++) { + document.getElementById('loader-text').textContent = `Processing page ${i} of ${numPages}...`; + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2.0 }); + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.height = viewport.height; + canvas.width = viewport.width; + await page.render({ canvasContext: context, viewport: viewport, canvas: canvas }).promise; + pageImages.push({ + data: canvas.toDataURL('image/jpeg', 0.8), + width: viewport.width, + height: viewport.height + }); + } + + document.getElementById('loader-text').textContent = 'Encrypting and building PDF...'; + const doc = new PDFDocument({ + size: [pageImages[0].width, pageImages[0].height], + pdfVersion: '1.7ext3', // Use 256-bit AES encryption + userPassword: password, + ownerPassword: password, + permissions: { + printing: 'highResolution', + modifying: false, + copying: false, + annotating: false, + fillingForms: false, + contentAccessibility: true, + documentAssembly: false + } + }); + const stream = doc.pipe(blobStream()); + for (let i = 0; i < pageImages.length; i++) { + if (i > 0) doc.addPage({ size: [pageImages[i].width, pageImages[i].height] }); + doc.image(pageImages[i].data, 0, 0, { width: pageImages[i].width, height: pageImages[i].height }); + } + doc.end(); + + stream.on('finish', function () { + const blob = stream.toBlob('application/pdf'); + downloadFile(blob, `encrypted-${file.name}`); + hideLoader(); + showAlert('Success', 'Encryption complete! Your download has started.'); + }); + } catch (error) { + console.error("Error during PDF encryption:", error); + hideLoader(); + showAlert('Error', 'An error occurred. The PDF might be corrupted.'); + } +} \ No newline at end of file diff --git a/src/js/logic/extract-pages.ts b/src/js/logic/extract-pages.ts new file mode 100644 index 0000000..31cbf18 --- /dev/null +++ b/src/js/logic/extract-pages.ts @@ -0,0 +1,61 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import JSZip from 'jszip'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function extractPages() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const pageInput = document.getElementById('pages-to-extract').value; + if (!pageInput.trim()) { + showAlert('Invalid Input', 'Please enter page numbers to extract.'); + return; + } + showLoader('Extracting pages...'); + try { + const totalPages = state.pdfDoc.getPageCount(); + const indicesToExtract = new Set(); + const ranges = pageInput.split(','); + + for (const range of ranges) { + const trimmedRange = range.trim(); + if (trimmedRange.includes('-')) { + const [start, end] = trimmedRange.split('-').map(Number); + if (isNaN(start) || isNaN(end) || start < 1 || end > totalPages || start > end) continue; + for (let i = start; i <= end; i++) indicesToExtract.add(i - 1); + } else { + const pageNum = Number(trimmedRange); + if (isNaN(pageNum) || pageNum < 1 || pageNum > totalPages) continue; + indicesToExtract.add(pageNum - 1); + } + } + + if (indicesToExtract.size === 0) { + showAlert('Invalid Input', 'No valid pages selected for extraction.'); + hideLoader(); + return; + } + + const zip = new JSZip(); + // @ts-expect-error TS(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message + const sortedIndices = Array.from(indicesToExtract).sort((a, b) => a - b); + + for (const index of sortedIndices) { + const newPdf = await PDFLibDocument.create(); + const [copiedPage] = await newPdf.copyPages(state.pdfDoc, [index as number]); + newPdf.addPage(copiedPage); + const newPdfBytes = await newPdf.save(); + // @ts-expect-error TS(2365) FIXME: Operator '+' cannot be applied to types 'unknown' ... Remove this comment to see the full error message + zip.file(`page-${index + 1}.pdf`, newPdfBytes); + } + + const zipBlob = await zip.generateAsync({ type: 'blob' }); + downloadFile(zipBlob, 'extracted-pages.zip'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not extract pages.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/fix-dimensions.ts b/src/js/logic/fix-dimensions.ts new file mode 100644 index 0000000..7121677 --- /dev/null +++ b/src/js/logic/fix-dimensions.ts @@ -0,0 +1,88 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, hexToRgb } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument, rgb, PageSizes } from 'pdf-lib'; + +export function setupFixDimensionsUI() { + const targetSizeSelect = document.getElementById('target-size'); + const customSizeWrapper = document.getElementById('custom-size-wrapper'); + if (targetSizeSelect && customSizeWrapper) { + targetSizeSelect.addEventListener('change', () => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + customSizeWrapper.classList.toggle('hidden', targetSizeSelect.value !== 'Custom'); + }); + } +} + +export async function fixDimensions() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const targetSizeKey = document.getElementById('target-size').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const orientation = document.getElementById('orientation').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + const scalingMode = document.querySelector('input[name="scaling-mode"]:checked').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const backgroundColor = hexToRgb(document.getElementById('background-color').value); + + showLoader('Standardizing pages...'); + try { + let targetWidth, targetHeight; + + if (targetSizeKey === 'Custom') { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const width = parseFloat(document.getElementById('custom-width').value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const height = parseFloat(document.getElementById('custom-height').value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const units = document.getElementById('custom-units').value; + if (units === 'in') { + targetWidth = width * 72; + targetHeight = height * 72; + } else { // mm + targetWidth = width * (72 / 25.4); + targetHeight = height * (72 / 25.4); + } + } else { + [targetWidth, targetHeight] = PageSizes[targetSizeKey]; + } + + if (orientation === 'landscape' && targetWidth < targetHeight) { + [targetWidth, targetHeight] = [targetHeight, targetWidth]; + } else if (orientation === 'portrait' && targetWidth > targetHeight) { + [targetWidth, targetHeight] = [targetHeight, targetWidth]; + } + + const sourceDoc = state.pdfDoc; + const newDoc = await PDFLibDocument.create(); + + for (const sourcePage of sourceDoc.getPages()) { + const { width: sourceWidth, height: sourceHeight } = sourcePage.getSize(); + const embeddedPage = await newDoc.embedPage(sourcePage); + + const newPage = newDoc.addPage([targetWidth, targetHeight]); + newPage.drawRectangle({ x: 0, y: 0, width: targetWidth, height: targetHeight, color: rgb(backgroundColor.r, backgroundColor.g, backgroundColor.b) }); + + const scaleX = targetWidth / sourceWidth; + const scaleY = targetHeight / sourceHeight; + const scale = scalingMode === 'fit' ? Math.min(scaleX, scaleY) : Math.max(scaleX, scaleY); + + const scaledWidth = sourceWidth * scale; + const scaledHeight = sourceHeight * scale; + + const x = (targetWidth - scaledWidth) / 2; + const y = (targetHeight - scaledHeight) / 2; + + newPage.drawPage(embeddedPage, { x, y, width: scaledWidth, height: scaledHeight }); + } + + const newPdfBytes = await newDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'standardized.pdf'); + + } catch (e) { + console.error(e); + showAlert('Error', 'An error occurred while standardizing pages.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/flatten.ts b/src/js/logic/flatten.ts new file mode 100644 index 0000000..15f604a --- /dev/null +++ b/src/js/logic/flatten.ts @@ -0,0 +1,27 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +export async function flatten() { + if (!state.pdfDoc) { + showAlert('Error', 'PDF not loaded.'); + return; + } + showLoader('Flattening PDF...'); + try { + const form = state.pdfDoc.getForm(); + form.flatten(); + + const flattenedBytes = await state.pdfDoc.save(); + downloadFile(new Blob([flattenedBytes], { type: 'application/pdf' }), 'flattened.pdf'); + } catch (e) { + console.error(e); + if (e.message.includes('getForm')) { + showAlert('No Form Found', 'This PDF does not contain any form fields to flatten.'); + } else { + showAlert('Error', 'Could not flatten the PDF.'); + } + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/form-filler.ts b/src/js/logic/form-filler.ts new file mode 100644 index 0000000..af079c7 --- /dev/null +++ b/src/js/logic/form-filler.ts @@ -0,0 +1,321 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import { + PDFDocument as PDFLibDocument, + PDFTextField, + PDFCheckBox, + PDFRadioGroup, + PDFDropdown, + PDFButton, + PDFSignature, + PDFOptionList +} from 'pdf-lib'; + +import * as pdfjsLib from 'pdfjs-dist'; + +pdfjsLib.GlobalWorkerOptions.workerSrc = new URL( + 'pdfjs-dist/build/pdf.worker.min.mjs', + import.meta.url +).toString(); + +let pdfJsDoc: any = null; +let currentPageNum = 1; +let pdfRendering = false; +let renderTimeout: any = null; +const formState = { + scale: 2, + fields: [], +}; + +let fieldValues: Record = {}; + +async function renderPage() { + if (pdfRendering || !pdfJsDoc) return; + + pdfRendering = true; + showLoader(`Rendering page ${currentPageNum}...`); + + const page = await pdfJsDoc.getPage(currentPageNum); + const viewport = page.getViewport({ scale: 1.0 }); + + const canvas = document.getElementById('pdf-canvas') as HTMLCanvasElement; + const context = canvas.getContext('2d'); + + if (!context) { + console.error('Could not get canvas context'); + pdfRendering = false; + hideLoader(); + return; + } + + canvas.height = viewport.height; + canvas.width = viewport.width; + + canvas.style.transformOrigin = 'top left'; + canvas.style.transform = `scale(${formState.scale})`; + + const tempPdfDoc = await PDFLibDocument.load(await state.pdfDoc.save(), { ignoreEncryption: true }); + const form = tempPdfDoc.getForm(); + Object.keys(fieldValues).forEach(fieldName => { + try { + const field = form.getField(fieldName); + if (!field) return; + + if (field instanceof PDFTextField) { + field.setText(fieldValues[fieldName]); + } else if (field instanceof PDFCheckBox) { + if (fieldValues[fieldName] === 'on') { + field.check(); + } else { + field.uncheck(); + } + } else if (field instanceof PDFRadioGroup) { + field.select(fieldValues[fieldName]); + } else if (field instanceof PDFDropdown) { + field.select(fieldValues[fieldName]); + } else if (field instanceof PDFOptionList) { + // Handle multi-select list box + if (Array.isArray(fieldValues[fieldName])) { + fieldValues[fieldName].forEach((option: any) => field.select(option)); + } + } + } catch (e) { + console.error(`Error applying value to field "${fieldName}":`, e); + } + }); + + const tempPdfBytes = await tempPdfDoc.save(); + const tempPdfJsDoc = await pdfjsLib.getDocument({ data: tempPdfBytes }).promise; + const tempPage = await tempPdfJsDoc.getPage(currentPageNum); + + // Use the newer PDF.js render API + await tempPage.render({ + canvasContext: context, + viewport: viewport + } as any).promise; + + const currentPageDisplay = document.getElementById('current-page-display'); + const totalPagesDisplay = document.getElementById('total-pages-display'); + const prevPageBtn = document.getElementById('prev-page') as HTMLButtonElement; + const nextPageBtn = document.getElementById('next-page') as HTMLButtonElement; + + if (currentPageDisplay) currentPageDisplay.textContent = String(currentPageNum); + if (totalPagesDisplay) totalPagesDisplay.textContent = String(pdfJsDoc.numPages); + if (prevPageBtn) prevPageBtn.disabled = currentPageNum <= 1; + if (nextPageBtn) nextPageBtn.disabled = currentPageNum >= pdfJsDoc.numPages; + + pdfRendering = false; + hideLoader(); +} + +/** + * Navigates to the next or previous page. + * @param {number} offset 1 for next, -1 for previous. + */ +async function changePage(offset: number) { + const newPageNum = currentPageNum + offset; + if (newPageNum > 0 && newPageNum <= pdfJsDoc.numPages) { + currentPageNum = newPageNum; + await renderPage(); + } +} + +/** + * Sets the zoom level of the PDF viewer. + * @param {number} factor The zoom factor. + */ +async function setZoom(factor: number) { + formState.scale = factor; + await renderPage(); +} + +function handleFormChange(event: Event) { + const input = event.target as HTMLInputElement | HTMLSelectElement; + const name = input.name; + let value: any; + + if (input instanceof HTMLInputElement && input.type === 'checkbox') { + value = input.checked ? 'on' : 'off'; + } else if (input instanceof HTMLSelectElement && input.multiple) { + // Handle multi-select list box + value = Array.from(input.options) + .filter(option => option.selected) + .map(option => option.value); + } else { + value = input.value; + } + + fieldValues[name] = value; + + clearTimeout(renderTimeout); + renderTimeout = setTimeout(() => { + renderPage(); + }, 350); +} + +function createFormFieldHtml(field: any) { + const name = field.getName(); + const isRequired = field.isRequired(); + + const labelText = name.replace(/[_-]/g, ' '); + const labelHtml = ``; + + let inputHtml = ''; + + if (field instanceof PDFTextField) { + fieldValues[name] = field.getText() || ''; + inputHtml = ``; + } else if (field instanceof PDFCheckBox) { + fieldValues[name] = field.isChecked() ? 'on' : 'off'; + inputHtml = ``; + } else if (field instanceof PDFRadioGroup) { + fieldValues[name] = field.getSelected(); + const options = field.getOptions(); + inputHtml = options.map((opt: any) => ` + + `).join(''); + } else if (field instanceof PDFDropdown) { + fieldValues[name] = field.getSelected(); + const dropdownOptions = field.getOptions(); + inputHtml = ``; + } else if (field instanceof PDFOptionList) { + const selectedValues = field.getSelected(); + fieldValues[name] = selectedValues; + const listOptions = field.getOptions(); + inputHtml = ``; + } else if (field instanceof PDFSignature) { + inputHtml = `

Signature field: Not supported for direct editing.

`; + } else if (field instanceof PDFButton) { + inputHtml = ``; + } else { + return `

Unsupported field type: ${field.constructor.name}

`; + } + + return ` +
+ ${labelHtml} + ${inputHtml} +
+ `; +} + +export async function setupFormFiller() { + if (!state.pdfDoc) return; + + showLoader('Analyzing form fields...'); + const formContainer = document.getElementById('form-fields-container'); + const processBtn = document.getElementById('process-btn'); + + if (!formContainer || !processBtn) { + console.error('Required DOM elements not found'); + hideLoader(); + return; + } + + try { + const form = state.pdfDoc.getForm(); + const fields = form.getFields(); + formState.fields = fields; + + if (fields.length === 0) { + formContainer.innerHTML = '

This PDF contains no form fields.

'; + processBtn.classList.add('hidden'); + } else { + let formHtml = ''; + + fields.forEach((field: any) => { + try { + formHtml += createFormFieldHtml(field); + } catch (e: any) { + console.error(`Error processing field "${field.getName()}":`, e); + formHtml += `

Unsupported field: ${field.getName()}

${e.message}

`; + } + }); + + formContainer.innerHTML = formHtml; + processBtn.classList.remove('hidden'); + + formContainer.addEventListener('change', handleFormChange); + formContainer.addEventListener('input', handleFormChange); + } + + const pdfBytes = await state.pdfDoc.save(); + pdfJsDoc = await pdfjsLib.getDocument({ data: pdfBytes }).promise; + currentPageNum = 1; + await renderPage(); + + const zoomInBtn = document.getElementById('zoom-in-btn'); + const zoomOutBtn = document.getElementById('zoom-out-btn'); + const prevPageBtn = document.getElementById('prev-page'); + const nextPageBtn = document.getElementById('next-page'); + + if (zoomInBtn) zoomInBtn.onclick = () => setZoom(formState.scale + 0.25); + if (zoomOutBtn) zoomOutBtn.onclick = () => setZoom(Math.max(0.25, formState.scale - 0.25)); + if (prevPageBtn) prevPageBtn.onclick = () => changePage(-1); + if (nextPageBtn) nextPageBtn.onclick = () => changePage(1); + + hideLoader(); + + const formFillerOptions = document.getElementById('form-filler-options'); + if (formFillerOptions) formFillerOptions.classList.remove('hidden'); + + } catch (e) { + console.error("Critical error setting up form filler:", e); + showAlert('Error', 'Failed to read PDF form data. The file may be corrupt or not a valid form.'); + hideLoader(); + } +} + +export async function processAndDownloadForm() { + showLoader('Applying form data...'); + try { + const form = state.pdfDoc.getForm(); + + Object.keys(fieldValues).forEach(fieldName => { + try { + const field = form.getField(fieldName); + const value = fieldValues[fieldName]; + + if (field instanceof PDFTextField) { + field.setText(value); + } else if (field instanceof PDFCheckBox) { + if (value === 'on') { + field.check(); + } else { + field.uncheck(); + } + } else if (field instanceof PDFRadioGroup) { + field.select(value); + } else if (field instanceof PDFDropdown) { + field.select(value); + } else if (field instanceof PDFOptionList) { + // Handle multi-select list box + if (Array.isArray(value)) { + value.forEach(option => field.select(option)); + } + } + } catch (e) { + console.error(`Error processing field "${fieldName}" during download:`, e); + } + }); + + const newPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'filled-form.pdf'); + + showAlert('Success', 'Form has been filled and downloaded.'); + + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to save the filled form.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/heic-to-pdf.ts b/src/js/logic/heic-to-pdf.ts new file mode 100644 index 0000000..c2f6560 --- /dev/null +++ b/src/js/logic/heic-to-pdf.ts @@ -0,0 +1,36 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import heic2any from 'heic2any'; +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function heicToPdf() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select at least one HEIC file.'); + return; + } + showLoader('Converting HEIC to PDF...'); + try { + const pdfDoc = await PDFLibDocument.create(); + for (const file of state.files) { + const conversionResult = await heic2any({ + blob: file, + toType: "image/png", + }); + const pngBlob = Array.isArray(conversionResult) ? conversionResult[0] : conversionResult; + const pngBytes = await pngBlob.arrayBuffer(); + + const pngImage = await pdfDoc.embedPng(pngBytes); + const page = pdfDoc.addPage([pngImage.width, pngImage.height]); + page.drawImage(pngImage, { x: 0, y: 0, width: pngImage.width, height: pngImage.height }); + } + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'from_heic.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert HEIC to PDF. One of the files may be invalid or unsupported.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/image-to-pdf.ts b/src/js/logic/image-to-pdf.ts new file mode 100644 index 0000000..c9e525d --- /dev/null +++ b/src/js/logic/image-to-pdf.ts @@ -0,0 +1,133 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +/** + * Converts any image into a standard, web-friendly JPEG. Loses transparency. + * @param {Uint8Array} imageBytes The raw bytes of the image file. + * @returns {Promise} A promise that resolves with sanitized JPEG bytes. + */ +function sanitizeImageAsJpeg(imageBytes: any) { + return new Promise((resolve, reject) => { + const blob = new Blob([imageBytes]); + const imageUrl = URL.createObjectURL(blob); + const img = new Image(); + + img.onload = () => { + const canvas = document.createElement('canvas'); + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + const ctx = canvas.getContext('2d'); + ctx.fillStyle = 'white'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(img, 0, 0); + canvas.toBlob( + async (jpegBlob) => { + if (!jpegBlob) return reject(new Error('Canvas to JPEG conversion failed.')); + resolve(new Uint8Array(await jpegBlob.arrayBuffer())); + }, 'image/jpeg', 0.9 + ); + URL.revokeObjectURL(imageUrl); + }; + img.onerror = () => { + URL.revokeObjectURL(imageUrl); + reject(new Error('File could not be loaded as an image.')); + }; + img.src = imageUrl; + }); +} + +/** + * Converts any image into a standard PNG. Preserves transparency. + * @param {Uint8Array} imageBytes The raw bytes of the image file. + * @returns {Promise} A promise that resolves with sanitized PNG bytes. + */ +function sanitizeImageAsPng(imageBytes: any) { + return new Promise((resolve, reject) => { + const blob = new Blob([imageBytes]); + const imageUrl = URL.createObjectURL(blob); + const img = new Image(); + + img.onload = () => { + const canvas = document.createElement('canvas'); + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + canvas.toBlob( + async (pngBlob) => { + if (!pngBlob) return reject(new Error('Canvas to PNG conversion failed.')); + resolve(new Uint8Array(await pngBlob.arrayBuffer())); + }, 'image/png' + ); + URL.revokeObjectURL(imageUrl); + }; + img.onerror = () => { + URL.revokeObjectURL(imageUrl); + reject(new Error('File could not be loaded as an image.')); + }; + img.src = imageUrl; + }); +} + + +export async function imageToPdf() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select at least one image file.'); + return; + } + showLoader('Converting images to PDF...'); + try { + const pdfDoc = await PDFLibDocument.create(); + const imageList = document.getElementById('image-list'); + const sortedFiles = Array.from(imageList.children) + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + .map(li => state.files.find(f => f.name === li.dataset.fileName)) + .filter(Boolean); + + for (const file of sortedFiles) { + const fileBuffer = await readFileAsArrayBuffer(file); + let image; + + if (file.type === 'image/jpeg') { + try { + image = await pdfDoc.embedJpg(fileBuffer as Uint8Array); + } catch (e) { + console.warn(`Direct JPG embedding failed for ${file.name}, sanitizing to JPG...`); + const sanitizedBytes = await sanitizeImageAsJpeg(fileBuffer); + image = await pdfDoc.embedJpg(sanitizedBytes as Uint8Array); + } + } else if (file.type === 'image/png') { + try { + image = await pdfDoc.embedPng(fileBuffer as Uint8Array); + } catch (e) { + console.warn(`Direct PNG embedding failed for ${file.name}, sanitizing to PNG...`); + const sanitizedBytes = await sanitizeImageAsPng(fileBuffer); + image = await pdfDoc.embedPng(sanitizedBytes as Uint8Array); + } + } else { + // For WebP and other types, convert to PNG to preserve transparency + console.warn(`Unsupported type "${file.type}" for ${file.name}, converting to PNG...`); + const sanitizedBytes = await sanitizeImageAsPng(fileBuffer); + image = await pdfDoc.embedPng(sanitizedBytes as Uint8Array); + } + + const page = pdfDoc.addPage([image.width, image.height]); + page.drawImage(image, { x: 0, y: 0, width: image.width, height: image.height }); + } + + if (pdfDoc.getPageCount() === 0) { + throw new Error("No valid images could be processed. Please check your files."); + } + + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'from-images.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', e.message || 'Failed to create PDF from images.'); + } finally { + hideLoader(); + } +} diff --git a/src/js/logic/index.ts b/src/js/logic/index.ts new file mode 100644 index 0000000..ab6b0e7 --- /dev/null +++ b/src/js/logic/index.ts @@ -0,0 +1,110 @@ +import { merge, setupMergeTool } from './merge.js'; +import { setupSplitTool, split } from './split.js'; +import { encrypt } from './encrypt.js'; +import { decrypt } from './decrypt.js'; +import { organize } from './organize.js'; +import { rotate } from './rotate.js'; +import { addPageNumbers } from './add-page-numbers.js'; +import { pdfToJpg } from './pdf-to-jpg.js'; +import { jpgToPdf } from './jpg-to-pdf.js'; +import { scanToPdf } from './scan-to-pdf.js'; +import { compress } from './compress.js'; +import { pdfToGreyscale } from './pdf-to-greyscale.js'; +import { pdfToZip } from './pdf-to-zip.js'; +import { editMetadata } from './edit-metadata.js'; +import { removeMetadata } from './remove-metadata.js'; +import { flatten } from './flatten.js'; +import { pdfToPng } from './pdf-to-png.js'; +import { pngToPdf } from './png-to-pdf.js'; +import { pdfToWebp } from './pdf-to-webp.js'; +import { webpToPdf } from './webp-to-pdf.js'; +import { deletePages } from './delete-pages.js'; +import { addBlankPage } from './add-blank-page.js'; +import { extractPages } from './extract-pages.js'; +import { addWatermark, setupWatermarkUI } from './add-watermark.js'; +import { addHeaderFooter } from './add-header-footer.js'; +import { imageToPdf } from './image-to-pdf.js'; +import { changePermissions } from './change-permissions.js'; +import { pdfToMarkdown } from './pdf-to-markdown.js'; +import { txtToPdf } from './txt-to-pdf.js'; +import { invertColors } from './invert-colors.js'; +// import { viewMetadata } from './view-metadata.js'; +import { reversePages } from './reverse-pages.js'; +import { mdToPdf } from './md-to-pdf.js'; +import { svgToPdf } from './svg-to-pdf.js'; +import { bmpToPdf } from './bmp-to-pdf.js'; +import { heicToPdf } from './heic-to-pdf.js'; +import { tiffToPdf } from './tiff-to-pdf.js'; +import { pdfToBmp } from './pdf-to-bmp.js'; +import { pdfToTiff } from './pdf-to-tiff.js'; +import { splitInHalf } from './split-in-half.js'; +import { analyzeAndDisplayDimensions } from './page-dimensions.js'; +import { nUpTool, setupNUpUI } from './n-up.js'; +import { processAndSave } from './duplicate-organize.js'; +import { combineToSinglePage } from './combine-single-page.js'; +import { fixDimensions, setupFixDimensionsUI } from './fix-dimensions.js'; +import { changeBackgroundColor } from './change-background-color.js'; +import { changeTextColor, setupTextColorTool } from './change-text-color.js'; +import { setupCompareTool } from './compare-pdfs.js'; +import { setupOcrTool } from './ocr-pdf.js'; +import { wordToPdf } from './word-to-pdf.js'; +import { applyAndSaveSignatures, setupSignTool } from './sign-pdf.js'; +import { removeAnnotations, setupRemoveAnnotationsTool } from './remove-annotations.js'; +import { setupCropperTool } from './cropper.js'; +import { processAndDownloadForm, setupFormFiller } from './form-filler.js'; + +export const toolLogic = { + merge: { process: merge, setup: setupMergeTool }, + split: { process: split, setup: setupSplitTool }, + encrypt, + decrypt, + organize, + rotate, + 'add-page-numbers': addPageNumbers, + 'pdf-to-jpg': pdfToJpg, + 'jpg-to-pdf': jpgToPdf, + 'scan-to-pdf': scanToPdf, + compress, + 'pdf-to-greyscale': pdfToGreyscale, + 'pdf-to-zip': pdfToZip, + 'edit-metadata': editMetadata, + 'remove-metadata': removeMetadata, + flatten, + 'pdf-to-png': pdfToPng, + 'png-to-pdf': pngToPdf, + 'pdf-to-webp': pdfToWebp, + 'webp-to-pdf': webpToPdf, + 'delete-pages': deletePages, + 'add-blank-page': addBlankPage, + 'extract-pages': extractPages, + 'add-watermark': { process: addWatermark, setup: setupWatermarkUI }, + 'add-header-footer': addHeaderFooter, + 'image-to-pdf': imageToPdf, + 'change-permissions': changePermissions, + 'pdf-to-markdown': pdfToMarkdown, + 'txt-to-pdf': txtToPdf, + 'invert-colors': invertColors, + 'reverse-pages': reversePages, + 'md-to-pdf': mdToPdf, + 'svg-to-pdf': svgToPdf, + 'bmp-to-pdf': bmpToPdf, + 'heic-to-pdf': heicToPdf, + 'tiff-to-pdf': tiffToPdf, + 'pdf-to-bmp': pdfToBmp, + 'pdf-to-tiff': pdfToTiff, + 'split-in-half': splitInHalf, + 'page-dimensions': analyzeAndDisplayDimensions, + 'n-up': { process: nUpTool, setup: setupNUpUI }, + 'duplicate-organize': { process: processAndSave }, + 'combine-single-page': combineToSinglePage, + 'fix-dimensions': { process: fixDimensions, setup: setupFixDimensionsUI }, + 'change-background-color': changeBackgroundColor, + 'change-text-color': { process: changeTextColor, setup: setupTextColorTool }, + 'compare-pdfs': { setup: setupCompareTool }, + 'ocr-pdf': { setup: setupOcrTool }, + 'word-to-pdf': wordToPdf, + 'sign-pdf': { process: applyAndSaveSignatures, setup: setupSignTool }, + 'remove-annotations': { process: removeAnnotations, setup: setupRemoveAnnotationsTool }, + 'cropper': { setup: setupCropperTool }, + 'form-filler': { process: processAndDownloadForm, setup: setupFormFiller}, +}; \ No newline at end of file diff --git a/src/js/logic/invert-colors.ts b/src/js/logic/invert-colors.ts new file mode 100644 index 0000000..54b4c1a --- /dev/null +++ b/src/js/logic/invert-colors.ts @@ -0,0 +1,53 @@ +// FILE: js/logic/invert-colors.js +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function invertColors() { + if (!state.pdfDoc) { showAlert('Error', 'PDF not loaded.'); return; } + showLoader('Inverting PDF colors...'); + try { + const newPdfDoc = await PDFLibDocument.create(); + const pdfBytes = await state.pdfDoc.save(); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdfjsDoc = await pdfjsLib.getDocument({ data: pdfBytes }).promise; + + for (let i = 1; i <= pdfjsDoc.numPages; i++) { + const page = await pdfjsDoc.getPage(i); + const viewport = page.getViewport({ scale: 1.5 }); + const canvas = document.createElement('canvas'); + canvas.width = viewport.width; + canvas.height = viewport.height; + const ctx = canvas.getContext('2d'); + await page.render({ canvasContext: ctx, viewport }).promise; + + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const data = imageData.data; + for (let j = 0; j < data.length; j += 4) { + data[j] = 255 - data[j]; // red + data[j + 1] = 255 - data[j + 1]; // green + data[j + 2] = 255 - data[j + 2]; // blue + } + ctx.putImageData(imageData, 0, 0); + + const pngImageBytes = await new Promise(resolve => canvas.toBlob(blob => { + const reader = new FileReader(); + // @ts-expect-error TS(2769) FIXME: No overload matches this call. + reader.onload = () => resolve(new Uint8Array(reader.result)); + reader.readAsArrayBuffer(blob); + }, 'image/png')); + + const image = await newPdfDoc.embedPng(pngImageBytes as ArrayBuffer); + const newPage = newPdfDoc.addPage([image.width, image.height]); + newPage.drawImage(image, { x: 0, y: 0, width: image.width, height: image.height }); + } + const newPdfBytes = await newPdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'inverted.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not invert PDF colors.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/jpg-to-pdf.ts b/src/js/logic/jpg-to-pdf.ts new file mode 100644 index 0000000..815a2d6 --- /dev/null +++ b/src/js/logic/jpg-to-pdf.ts @@ -0,0 +1,93 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +/** + * Takes any image byte array and uses the browser's canvas to convert it + * into a standard, web-friendly (baseline, sRGB) JPEG byte array. + * @param {Uint8Array} imageBytes The raw bytes of the image file. + * @returns {Promise} A promise that resolves with the sanitized JPEG bytes. + */ +function sanitizeImageAsJpeg(imageBytes: any) { + return new Promise((resolve, reject) => { + const blob = new Blob([imageBytes]); + const imageUrl = URL.createObjectURL(blob); + const img = new Image(); + + img.onload = () => { + const canvas = document.createElement('canvas'); + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + + canvas.toBlob( + async (jpegBlob) => { + if (!jpegBlob) { + return reject(new Error('Canvas toBlob conversion failed.')); + } + const arrayBuffer = await jpegBlob.arrayBuffer(); + resolve(new Uint8Array(arrayBuffer)); + }, + 'image/jpeg', + 0.9 + ); + URL.revokeObjectURL(imageUrl); + }; + + img.onerror = () => { + URL.revokeObjectURL(imageUrl); + reject(new Error('The provided file could not be loaded as an image. It may be corrupted.')); + }; + + img.src = imageUrl; + }); +} + +export async function jpgToPdf() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select at least one JPG file.'); + return; + } + showLoader('Creating PDF from JPGs...'); + try { + const pdfDoc = await PDFLibDocument.create(); + + for (const file of state.files) { + const originalBytes = await readFileAsArrayBuffer(file); + let jpgImage; + + try { + jpgImage = await pdfDoc.embedJpg(originalBytes as Uint8Array); + } catch (e) { + // @ts-expect-error TS(2554) FIXME: Expected 2 arguments, but got 1. + showAlert(`Direct JPG embedding failed for ${file.name}, attempting to sanitize...`); + try { + const sanitizedBytes = await sanitizeImageAsJpeg(originalBytes); + jpgImage = await pdfDoc.embedJpg(sanitizedBytes as Uint8Array); + } catch (fallbackError) { + console.error(`Failed to process ${file.name} after sanitization:`, fallbackError); + throw new Error(`Could not process "${file.name}". The file may be corrupted.`); + } + } + + const page = pdfDoc.addPage([jpgImage.width, jpgImage.height]); + page.drawImage(jpgImage, { + x: 0, + y: 0, + width: jpgImage.width, + height: jpgImage.height, + }); + } + + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'from_jpgs.pdf'); + } catch (e) { + console.error(e); + showAlert('Conversion Error', e.message); + } finally { + hideLoader(); + } +} diff --git a/src/js/logic/md-to-pdf.ts b/src/js/logic/md-to-pdf.ts new file mode 100644 index 0000000..5390468 --- /dev/null +++ b/src/js/logic/md-to-pdf.ts @@ -0,0 +1,85 @@ +// note: this is a work in progress +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import html2canvas from 'html2canvas'; + + +export async function mdToPdf() { + // @ts-expect-error TS(2339) FIXME: Property 'jspdf' does not exist on type 'Window & ... Remove this comment to see the full error message + if (typeof window.jspdf === 'undefined' || typeof window.html2canvas === 'undefined') { + showAlert('Libraries Not Ready', 'PDF generation libraries are loading. Please try again.'); + return; + } + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const markdownContent = document.getElementById('md-input').value.trim(); + if (!markdownContent) { + showAlert('Input Required', 'Please enter some Markdown text.'); + return; + } + showLoader('Generating High-Quality PDF...'); + + try { + // @ts-expect-error TS(2304) FIXME: Cannot find name 'marked'. + const htmlContent = marked.parse(markdownContent); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const pageFormat = document.getElementById('page-format').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const orientation = document.getElementById('orientation').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const marginSize = document.getElementById('margin-size').value; + + const tempContainer = document.createElement('div'); + tempContainer.style.cssText = 'position: absolute; top: -9999px; left: -9999px; width: 800px; padding: 40px; background: white; color: black;'; + const styleSheet = document.createElement('style'); + styleSheet.textContent = ` + body { font-family: Helvetica, Arial, sans-serif; line-height: 1.6; font-size: 12px; } + h1, h2, h3 { margin: 20px 0 10px 0; font-weight: 600; border-bottom: 1px solid #eaecef; padding-bottom: .3em; } + h1 { font-size: 2em; } h2 { font-size: 1.5em; } + p, blockquote, ul, ol, pre, table { margin: 0 0 16px 0; } + blockquote { padding: 0 1em; color: #6a737d; border-left: .25em solid #dfe2e5; } + pre { padding: 16px; overflow: auto; font-size: 85%; line-height: 1.45; background-color: #f6f8fa; border-radius: 6px; } + code { font-family: 'Courier New', monospace; background-color: rgba(27,31,35,.05); border-radius: 3px; padding: .2em .4em; } + table { width: 100%; border-collapse: collapse; } th, td { padding: 6px 13px; border: 1px solid #dfe2e5; } + img { max-width: 100%; } + `; + tempContainer.appendChild(styleSheet); + tempContainer.innerHTML += htmlContent; + document.body.appendChild(tempContainer); + + const canvas = await html2canvas(tempContainer, { scale: 2, useCORS: true }); + document.body.removeChild(tempContainer); + + // @ts-expect-error TS(2339) FIXME: Property 'jspdf' does not exist on type 'Window & ... Remove this comment to see the full error message + const { jsPDF } = window.jspdf; + const pdf = new jsPDF({ orientation, unit: 'mm', format: pageFormat }); + const pageFormats = { 'a4': [210, 297], 'letter': [216, 279] }; + const format = pageFormats[pageFormat]; + const [pageWidth, pageHeight] = orientation === 'landscape' ? [format[1], format[0]] : format; + const margins = { 'narrow': 10, 'normal': 20, 'wide': 30 }; + const margin = margins[marginSize]; + const contentWidth = pageWidth - (margin * 2); + const contentHeight = pageHeight - (margin * 2); + const imgData = canvas.toDataURL('image/png'); + const imgHeight = (canvas.height * contentWidth) / canvas.width; + + let heightLeft = imgHeight; + let position = margin; + pdf.addImage(imgData, 'PNG', margin, position, contentWidth, imgHeight); + heightLeft -= contentHeight; + + while (heightLeft > 0) { + position = position - pageHeight; + pdf.addPage(); + pdf.addImage(imgData, 'PNG', margin, position, contentWidth, imgHeight); + heightLeft -= contentHeight; + } + + const pdfBlob = pdf.output('blob'); + downloadFile(pdfBlob, 'markdown-document.pdf'); + } catch (error) { + console.error('MD to PDF conversion error:', error); + showAlert('Conversion Error', 'Failed to generate PDF.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/merge.ts b/src/js/logic/merge.ts new file mode 100644 index 0000000..547cb85 --- /dev/null +++ b/src/js/logic/merge.ts @@ -0,0 +1,396 @@ +import { showLoader, hideLoader, showAlert } from '../ui.ts'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.ts'; +import { state } from '../state.ts'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; +import * as pdfjsLib from 'pdfjs-dist'; +import Sortable from 'sortablejs'; + +pdfjsLib.GlobalWorkerOptions.workerSrc = new URL( + 'pdfjs-dist/build/pdf.worker.min.mjs', + import.meta.url +).toString(); + +const mergeState = { + pdfDocs: {}, + activeMode: 'file', + sortableInstances: {}, + isRendering: false, + cachedThumbnails: null, + lastFileHash: null +}; + +function parsePageRanges(rangeString: any, totalPages: any) { + const indices = new Set(); + if (!rangeString.trim()) return []; + + const ranges = rangeString.split(','); + for (const range of ranges) { + const trimmedRange = range.trim(); + if (trimmedRange.includes('-')) { + const [start, end] = trimmedRange.split('-').map(Number); + if (isNaN(start) || isNaN(end) || start < 1 || end > totalPages || start > end) continue; + for (let i = start; i <= end; i++) { + indices.add(i - 1); + } + } else { + const pageNum = Number(trimmedRange); + if (isNaN(pageNum) || pageNum < 1 || pageNum > totalPages) continue; + indices.add(pageNum - 1); + } + } + // @ts-expect-error TS(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message + return Array.from(indices).sort((a, b) => a - b); +} + +function initializeFileListSortable() { + const fileList = document.getElementById('file-list'); + if (!fileList) return; + + // @ts-expect-error TS(2339) FIXME: Property 'fileList' does not exist on type '{}'. + if (mergeState.sortableInstances.fileList) { + // @ts-expect-error TS(2339) FIXME: Property 'fileList' does not exist on type '{}'. + mergeState.sortableInstances.fileList.destroy(); + } + + // @ts-expect-error TS(2339) FIXME: Property 'fileList' does not exist on type '{}'. + mergeState.sortableInstances.fileList = Sortable.create(fileList, { + handle: '.drag-handle', + animation: 150, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + onStart: function (evt: any) { + evt.item.style.opacity = '0.5'; + }, + onEnd: function (evt: any) { + evt.item.style.opacity = '1'; + } + }); +} + +function initializePageThumbnailsSortable() { + const container = document.getElementById('page-merge-preview'); + if (!container) return; + + // @ts-expect-error TS(2339) FIXME: Property 'pageThumbnails' does not exist on type '... Remove this comment to see the full error message + if (mergeState.sortableInstances.pageThumbnails) { + // @ts-expect-error TS(2339) FIXME: Property 'pageThumbnails' does not exist on type '... Remove this comment to see the full error message + mergeState.sortableInstances.pageThumbnails.destroy(); + } + + // @ts-expect-error TS(2339) FIXME: Property 'pageThumbnails' does not exist on type '... Remove this comment to see the full error message + mergeState.sortableInstances.pageThumbnails = Sortable.create(container, { + animation: 150, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + onStart: function (evt: any) { + evt.item.style.opacity = '0.5'; + }, + onEnd: function (evt: any) { + evt.item.style.opacity = '1'; + } + }); +} + +function generateFileHash() { + return (state.files as File[]).map(f => `${f.name}-${f.size}-${f.lastModified}`).join('|'); +} + +async function renderPageMergeThumbnails() { + const container = document.getElementById('page-merge-preview'); + if (!container) return; + + const currentFileHash = generateFileHash(); + const filesChanged = currentFileHash !== mergeState.lastFileHash; + + if (!filesChanged && mergeState.cachedThumbnails !== null) { + // Simple check to see if it's already rendered to avoid flicker. + if (container.firstChild) { + initializePageThumbnailsSortable(); + return; + } + } + + if (mergeState.isRendering) { + return; + } + + mergeState.isRendering = true; + container.textContent = ''; + + let currentPageNumber = 0; + let totalPages = state.files.reduce((sum, file) => { + const pdfDoc = mergeState.pdfDocs[file.name]; + return sum + (pdfDoc ? pdfDoc.getPageCount() : 0); + }, 0); + + try { + const thumbnailsHTML = []; + + for (const file of state.files) { + const pdfDoc = mergeState.pdfDocs[file.name]; + if (!pdfDoc) continue; + + const pdfData = await pdfDoc.save(); + const pdfjsDoc = await pdfjsLib.getDocument({ data: pdfData }).promise; + + for (let i = 1; i <= pdfjsDoc.numPages; i++) { + currentPageNumber++; + showLoader(`Rendering page previews: ${currentPageNumber}/${totalPages}`); + const page = await pdfjsDoc.getPage(i); + const viewport = page.getViewport({ scale: 0.3 }); + const canvas = document.createElement('canvas'); + canvas.height = viewport.height; + canvas.width = viewport.width; + const context = canvas.getContext('2d')!; + await page.render({ + canvasContext: context, + canvas: canvas, + viewport + }).promise; + + const wrapper = document.createElement('div'); + wrapper.className = 'page-thumbnail relative cursor-move flex flex-col items-center gap-1 p-2 border-2 border-gray-600 hover:border-indigo-500 rounded-lg bg-gray-700 transition-colors'; + wrapper.dataset.fileName = file.name; + wrapper.dataset.pageIndex = (i - 1).toString(); + + const imgContainer = document.createElement('div'); + imgContainer.className = 'relative'; + + const img = document.createElement('img'); + img.src = canvas.toDataURL(); + img.className = 'rounded-md shadow-md max-w-full h-auto'; + + const pageNumDiv = document.createElement('div'); + pageNumDiv.className = 'absolute top-1 left-1 bg-indigo-600 text-white text-xs px-2 py-1 rounded-md font-semibold shadow-lg'; + pageNumDiv.textContent = i.toString(); + + imgContainer.append(img, pageNumDiv); + + const fileNamePara = document.createElement('p'); + fileNamePara.className = 'text-xs text-gray-400 truncate w-full text-center'; + const fullTitle = `${file.name} (page ${i})`; + fileNamePara.title = fullTitle; + fileNamePara.textContent = `${file.name.substring(0, 10)}... (p${i})`; + + wrapper.append(imgContainer, fileNamePara); + container.appendChild(wrapper); + } + + pdfjsDoc.destroy(); + } + + mergeState.cachedThumbnails = true; + mergeState.lastFileHash = currentFileHash; + + initializePageThumbnailsSortable(); + } catch (error) { + console.error('Error rendering page thumbnails:', error); + showAlert('Error', 'Failed to render page thumbnails'); + } finally { + hideLoader(); + mergeState.isRendering = false; + } +} + +export async function merge() { + showLoader('Merging PDFs...'); + try { + const newPdfDoc = await PDFLibDocument.create(); + + if (mergeState.activeMode === 'file') { + const fileList = document.getElementById('file-list'); + const sortedFiles = Array.from(fileList.children).map(li => { + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + return state.files.find(f => f.name === li.dataset.fileName); + }).filter(Boolean); + + for (const file of sortedFiles) { + const safeFileName = file.name.replace(/[^a-zA-Z0-9]/g, '_'); + const rangeInput = document.getElementById(`range-${safeFileName}`); + if (!rangeInput) continue; + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const rangeInputValue = rangeInput.value; + const sourcePdf = mergeState.pdfDocs[file.name]; + if (!sourcePdf) continue; + + const totalPages = sourcePdf.getPageCount(); + const pageIndices = parsePageRanges(rangeInputValue, totalPages); + + const indicesToCopy = pageIndices.length > 0 ? pageIndices : sourcePdf.getPageIndices(); + const copiedPages = await newPdfDoc.copyPages(sourcePdf, indicesToCopy); + copiedPages.forEach((page: any) => newPdfDoc.addPage(page)); + } + + } else { + const pageContainer = document.getElementById('page-merge-preview'); + const pageElements = Array.from(pageContainer.children); + + for (const el of pageElements) { + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + const fileName = el.dataset.fileName; + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + const pageIndex = parseInt(el.dataset.pageIndex, 10); + + const sourcePdf = mergeState.pdfDocs[fileName]; + if (sourcePdf && !isNaN(pageIndex)) { + const [copiedPage] = await newPdfDoc.copyPages(sourcePdf, [pageIndex]); + newPdfDoc.addPage(copiedPage); + } + } + } + + const mergedPdfBytes = await newPdfDoc.save(); + downloadFile(new Blob([mergedPdfBytes], { type: 'application/pdf' }), 'merged.pdf'); + showAlert('Success', 'PDFs merged successfully!'); + + } catch (e) { + console.error('Merge error:', e); + showAlert('Error', 'Failed to merge PDFs. Please check that all files are valid and not password-protected.'); + } finally { + hideLoader(); + } +} + +export async function setupMergeTool() { + document.getElementById('merge-options').classList.remove('hidden'); + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + document.getElementById('process-btn').disabled = false; + + const wasInPageMode = mergeState.activeMode === 'page'; + + showLoader('Loading PDF documents...'); + try { + for (const file of state.files) { + if (!mergeState.pdfDocs[file.name]) { + const pdfBytes = await readFileAsArrayBuffer(file); + mergeState.pdfDocs[file.name] = await PDFLibDocument.load(pdfBytes as ArrayBuffer, { + ignoreEncryption: true + }); + } + } + } catch (error) { + console.error('Error loading PDFs:', error); + showAlert('Error', 'Failed to load one or more PDF files'); + return; + } finally { + hideLoader(); + } + + const fileModeBtn = document.getElementById('file-mode-btn'); + const pageModeBtn = document.getElementById('page-mode-btn'); + const filePanel = document.getElementById('file-mode-panel'); + const pagePanel = document.getElementById('page-mode-panel'); + const fileList = document.getElementById('file-list'); + + fileList.textContent = ''; // Clear list safely + (state.files as File[]).forEach(f => { + const doc = mergeState.pdfDocs[f.name]; + const pageCount = doc ? doc.getPageCount() : 'N/A'; + const safeFileName = f.name.replace(/[^a-zA-Z0-9]/g, '_'); + + const li = document.createElement('li'); + li.className = 'bg-gray-700 p-3 rounded-lg border border-gray-600 hover:border-indigo-500 transition-colors'; + li.dataset.fileName = f.name; + + const mainDiv = document.createElement('div'); + mainDiv.className = 'flex items-center justify-between'; + + const nameSpan = document.createElement('span'); + nameSpan.className = 'truncate font-medium text-white flex-1 mr-2'; + nameSpan.title = f.name; + nameSpan.textContent = f.name; + + const dragHandle = document.createElement('div'); + dragHandle.className = 'drag-handle cursor-move text-gray-400 hover:text-white p-1 rounded transition-colors'; + dragHandle.innerHTML = ``; // Safe: static content + + mainDiv.append(nameSpan, dragHandle); + + const rangeDiv = document.createElement('div'); + rangeDiv.className = 'mt-2'; + + const label = document.createElement('label'); + label.htmlFor = `range-${safeFileName}`; + label.className = 'text-xs text-gray-400'; + label.textContent = `Pages (e.g., 1-3, 5) - Total: ${pageCount}`; + + const input = document.createElement('input'); + input.type = 'text'; + input.id = `range-${safeFileName}`; + input.className = 'w-full bg-gray-800 border border-gray-600 text-white rounded-md p-2 text-sm mt-1 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-colors'; + input.placeholder = 'Leave blank for all pages'; + + rangeDiv.append(label, input); + li.append(mainDiv, rangeDiv); + fileList.appendChild(li); + }); + + initializeFileListSortable(); + + const newFileModeBtn = fileModeBtn.cloneNode(true); + const newPageModeBtn = pageModeBtn.cloneNode(true); + fileModeBtn.replaceWith(newFileModeBtn); + pageModeBtn.replaceWith(newPageModeBtn); + + newFileModeBtn.addEventListener('click', () => { + if (mergeState.activeMode === 'file') return; + + mergeState.activeMode = 'file'; + filePanel.classList.remove('hidden'); + pagePanel.classList.add('hidden'); + + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newFileModeBtn.classList.add('bg-indigo-600', 'text-white'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newFileModeBtn.classList.remove('bg-gray-700', 'text-gray-300'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newPageModeBtn.classList.remove('bg-indigo-600', 'text-white'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newPageModeBtn.classList.add('bg-gray-700', 'text-gray-300'); + }); + + newPageModeBtn.addEventListener('click', async () => { + if (mergeState.activeMode === 'page') return; + + mergeState.activeMode = 'page'; + filePanel.classList.add('hidden'); + pagePanel.classList.remove('hidden'); + + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newPageModeBtn.classList.add('bg-indigo-600', 'text-white'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newPageModeBtn.classList.remove('bg-gray-700', 'text-gray-300'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newFileModeBtn.classList.remove('bg-indigo-600', 'text-white'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newFileModeBtn.classList.add('bg-gray-700', 'text-gray-300'); + + await renderPageMergeThumbnails(); + }); + + if (wasInPageMode) { + mergeState.activeMode = 'page'; + filePanel.classList.add('hidden'); + pagePanel.classList.remove('hidden'); + + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newPageModeBtn.classList.add('bg-indigo-600', 'text-white'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newPageModeBtn.classList.remove('bg-gray-700', 'text-gray-300'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newFileModeBtn.classList.remove('bg-indigo-600', 'text-white'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newFileModeBtn.classList.add('bg-gray-700', 'text-gray-300'); + + await renderPageMergeThumbnails(); + } else { + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newFileModeBtn.classList.add('bg-indigo-600', 'text-white'); + // @ts-expect-error TS(2339) FIXME: Property 'classList' does not exist on type 'Node'... Remove this comment to see the full error message + newPageModeBtn.classList.add('bg-gray-700', 'text-gray-300'); + } +} \ No newline at end of file diff --git a/src/js/logic/n-up.ts b/src/js/logic/n-up.ts new file mode 100644 index 0000000..79a2772 --- /dev/null +++ b/src/js/logic/n-up.ts @@ -0,0 +1,111 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, hexToRgb } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument, rgb, PageSizes } from 'pdf-lib'; + +export function setupNUpUI() { + const addBorderCheckbox = document.getElementById('add-border'); + const borderColorWrapper = document.getElementById('border-color-wrapper'); + if (addBorderCheckbox && borderColorWrapper) { + addBorderCheckbox.addEventListener('change', () => { + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + borderColorWrapper.classList.toggle('hidden', !addBorderCheckbox.checked); + }); + } +} + +export async function nUpTool() { + // 1. Gather all options from the UI + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const n = parseInt(document.getElementById('pages-per-sheet').value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const pageSizeKey = document.getElementById('output-page-size').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + let orientation = document.getElementById('output-orientation').value; + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + const useMargins = document.getElementById('add-margins').checked; + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + const addBorder = document.getElementById('add-border').checked; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const borderColor = hexToRgb(document.getElementById('border-color').value); + + showLoader('Creating N-Up PDF...'); + try { + const sourceDoc = state.pdfDoc; + const newDoc = await PDFLibDocument.create(); + const sourcePages = sourceDoc.getPages(); + + const gridDims = { 2: [2, 1], 4: [2, 2], 9: [3, 3], 16: [4, 4] }[n]; + + let [pageWidth, pageHeight] = PageSizes[pageSizeKey]; + + if (orientation === 'auto') { + const firstPage = sourcePages[0]; + const isSourceLandscape = firstPage.getWidth() > firstPage.getHeight(); + // If source is landscape and grid is wider than tall (like 2x1), output landscape. + orientation = (isSourceLandscape && gridDims[0] > gridDims[1]) ? 'landscape' : 'portrait'; + } + if (orientation === 'landscape' && pageWidth < pageHeight) { + [pageWidth, pageHeight] = [pageHeight, pageWidth]; + } + + const margin = useMargins ? 36 : 0; + const gutter = useMargins ? 10 : 0; + + const usableWidth = pageWidth - (margin * 2); + const usableHeight = pageHeight - (margin * 2); + + // Loop through the source pages in chunks of 'n' + for (let i = 0; i < sourcePages.length; i += n) { + showLoader(`Processing sheet ${Math.floor(i / n) + 1}...`); + const chunk = sourcePages.slice(i, i + n); + const outputPage = newDoc.addPage([pageWidth, pageHeight]); + + // Calculate dimensions of each cell in the grid + const cellWidth = (usableWidth - (gutter * (gridDims[0] - 1))) / gridDims[0]; + const cellHeight = (usableHeight - (gutter * (gridDims[1] - 1))) / gridDims[1]; + + for (let j = 0; j < chunk.length; j++) { + const sourcePage = chunk[j]; + const embeddedPage = await newDoc.embedPage(sourcePage); + + // Calculate scaled dimensions to fit the cell, preserving aspect ratio + const scale = Math.min(cellWidth / embeddedPage.width, cellHeight / embeddedPage.height); + const scaledWidth = embeddedPage.width * scale; + const scaledHeight = embeddedPage.height * scale; + + // Calculate position (x, y) for this cell + const row = Math.floor(j / gridDims[0]); + const col = j % gridDims[0]; + const cellX = margin + col * (cellWidth + gutter); + const cellY = pageHeight - margin - (row + 1) * cellHeight - row * gutter; + + // Center the page within its cell + const x = cellX + (cellWidth - scaledWidth) / 2; + const y = cellY + (cellHeight - scaledHeight) / 2; + + outputPage.drawPage(embeddedPage, { x, y, width: scaledWidth, height: scaledHeight }); + + if (addBorder) { + outputPage.drawRectangle({ + x, y, + width: scaledWidth, + height: scaledHeight, + borderColor: rgb(borderColor.r, borderColor.g, borderColor.b), + borderWidth: 1, + }); + } + } + } + + const newPdfBytes = await newDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), `n-up_${n}.pdf`); + } catch (e) { + console.error(e); + showAlert('Error', 'An error occurred while creating the N-Up PDF.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/ocr-pdf.ts b/src/js/logic/ocr-pdf.ts new file mode 100644 index 0000000..9742e64 --- /dev/null +++ b/src/js/logic/ocr-pdf.ts @@ -0,0 +1,278 @@ +import { tesseractLanguages } from '../config/tesseract-languages.js'; +import { showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import Tesseract from 'tesseract.js'; +import { PDFDocument as PDFLibDocument, StandardFonts, rgb } from 'pdf-lib'; +import { icons, createIcons } from "lucide"; + +let searchablePdfBytes: any = null; + + +function sanitizeTextForWinAnsi(text: string): string { + // Remove invisible Unicode control characters (like Left-to-Right Mark U+200E) + return text.replace(/[\u0000-\u001F\u007F-\u009F\u200E\u200F\u202A-\u202E\uFEFF]/g, '') + .replace(/[^\u0020-\u007E\u00A0-\u00FF]/g, ''); +} + +function parseHOCR(hocrText: string) { + const parser = new DOMParser(); + const doc = parser.parseFromString(hocrText, 'text/html'); + const words = []; + + // Find all word elements in hOCR + const wordElements = doc.querySelectorAll('.ocrx_word'); + + wordElements.forEach((wordEl) => { + const titleAttr = wordEl.getAttribute('title'); + const text = wordEl.textContent?.trim() || ''; + + if (!titleAttr || !text) return; + + // Parse bbox coordinates from title attribute + // Format: "bbox x0 y0 x1 y1; x_wconf confidence" + const bboxMatch = titleAttr.match(/bbox (\d+) (\d+) (\d+) (\d+)/); + const confMatch = titleAttr.match(/x_wconf (\d+)/); + + if (bboxMatch) { + words.push({ + text: text, + bbox: { + x0: parseInt(bboxMatch[1]), + y0: parseInt(bboxMatch[2]), + x1: parseInt(bboxMatch[3]), + y1: parseInt(bboxMatch[4]) + }, + confidence: confMatch ? parseInt(confMatch[1]) : 0 + }); + } + }); + + return words; +} + +function binarizeCanvas(ctx: any) { + const imageData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height); + const data = imageData.data; + for (let i = 0; i < data.length; i += 4) { + // A simple luminance-based threshold for determining black or white + const brightness = 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2]; + const color = brightness > 128 ? 255 : 0; // If brighter than mid-gray, make it white, otherwise black + data[i] = data[i + 1] = data[i + 2] = color; + } + ctx.putImageData(imageData, 0, 0); +} + +function updateProgress(status: any, progress: any) { + const progressBar = document.getElementById('progress-bar'); + const progressStatus = document.getElementById('progress-status'); + const progressLog = document.getElementById('progress-log'); + + if (!progressBar || !progressStatus || !progressLog) return; + + progressStatus.textContent = status; + // Tesseract's progress can sometimes exceed 1, so we cap it at 100%. + progressBar.style.width = `${Math.min(100, progress * 100)}%`; + + const logMessage = `Status: ${status}`; + progressLog.textContent += logMessage + '\n'; + progressLog.scrollTop = progressLog.scrollHeight; +} + + +async function runOCR() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + const selectedLangs = Array.from(document.querySelectorAll('.lang-checkbox:checked')).map(cb => cb.value); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const scale = parseFloat(document.getElementById('ocr-resolution').value); + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + const binarize = document.getElementById('ocr-binarize').checked; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const whitelist = document.getElementById('ocr-whitelist').value; + + if (selectedLangs.length === 0) { + showAlert('No Languages Selected', 'Please select at least one language for OCR.'); + return; + } + const langString = selectedLangs.join('+'); + + document.getElementById('ocr-options').classList.add('hidden'); + document.getElementById('ocr-progress').classList.remove('hidden'); + + try { + const worker = await Tesseract.createWorker(langString, 1, { + logger: (m: any) => updateProgress(m.status, m.progress || 0) + }); + + // Enable hOCR output + await worker.setParameters({ + tessjs_create_hocr: '1', + }); + + if (whitelist.trim()) { + await worker.setParameters({ + tessedit_char_whitelist: whitelist.trim(), + }); + } + + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + const newPdfDoc = await PDFLibDocument.create(); + const font = await newPdfDoc.embedFont(StandardFonts.Helvetica); + let fullText = ''; + + for (let i = 1; i <= pdf.numPages; i++) { + updateProgress(`Processing page ${i} of ${pdf.numPages}`, (i - 1) / pdf.numPages); + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale }); + const canvas = document.createElement('canvas'); + canvas.width = viewport.width; + canvas.height = viewport.height; + const context = canvas.getContext('2d'); + await page.render({ canvasContext: context, viewport }).promise; + + if (binarize) { + binarizeCanvas(context); + } + + const result = await worker.recognize(canvas); + const data = result.data; + const newPage = newPdfDoc.addPage([viewport.width, viewport.height]); + const pngImageBytes = await new Promise(resolve => canvas.toBlob(blob => { + const reader = new FileReader(); + // @ts-expect-error TS(2769) FIXME: No overload matches this call. + reader.onload = () => resolve(new Uint8Array(reader.result)); + reader.readAsArrayBuffer(blob); + }, 'image/png')); + const pngImage = await newPdfDoc.embedPng(pngImageBytes as ArrayBuffer); + newPage.drawImage(pngImage, { x: 0, y: 0, width: viewport.width, height: viewport.height }); + + // Parse hOCR to get word-level data + if (data.hocr) { + const words = parseHOCR(data.hocr); + + words.forEach((word: any) => { + const { x0, y0, x1, y1 } = word.bbox; + // Sanitize the text to remove characters WinAnsi cannot encode + const text = sanitizeTextForWinAnsi(word.text); + + // Skip words that become empty after sanitization + if (!text.trim()) return; + + const bboxWidth = x1 - x0; + const bboxHeight = y1 - y0; + + let fontSize = bboxHeight * 0.9; + let textWidth = font.widthOfTextAtSize(text, fontSize); + while (textWidth > bboxWidth && fontSize > 1) { + fontSize -= 0.5; + textWidth = font.widthOfTextAtSize(text, fontSize); + } + + try { + newPage.drawText(text, { + x: x0, + y: viewport.height - y1 + (bboxHeight - fontSize) / 2, + font, + size: fontSize, + color: rgb(0, 0, 0), + opacity: 0, + }); + } catch (error) { + // If drawing fails despite sanitization, log and skip this word + console.warn(`Could not draw text "${text}":`, error); + } + }); + } + + fullText += data.text + '\n\n'; + } + + await worker.terminate(); + + searchablePdfBytes = await newPdfDoc.save(); + document.getElementById('ocr-progress').classList.add('hidden'); + document.getElementById('ocr-results').classList.remove('hidden'); + + createIcons({icons}); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + document.getElementById('ocr-text-output').value = fullText.trim(); + + document.getElementById('download-searchable-pdf').addEventListener('click', () => { + downloadFile(new Blob([searchablePdfBytes], { type: 'application/pdf' }), 'searchable.pdf'); + }); + + // CHANGE: The copy button logic is updated to be safer. + document.getElementById('copy-text-btn').addEventListener('click', (e) => { + const button = e.currentTarget as HTMLButtonElement; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... + const textToCopy = document.getElementById('ocr-text-output').value; + + navigator.clipboard.writeText(textToCopy).then(() => { + button.textContent = ''; // Clear the button safely + const icon = document.createElement('i'); + icon.setAttribute('data-lucide', 'check'); + icon.className = 'w-4 h-4 text-green-400'; + button.appendChild(icon); + createIcons({ icons }); + + setTimeout(() => { + const currentButton = document.getElementById('copy-text-btn'); + if (currentButton) { + currentButton.textContent = ''; // Clear the button safely + const resetIcon = document.createElement('i'); + resetIcon.setAttribute('data-lucide', 'clipboard-copy'); + resetIcon.className = 'w-4 h-4 text-gray-300'; + currentButton.appendChild(resetIcon); + createIcons({ icons }); + } + }, 2000); + }); + }); + + document.getElementById('download-txt-btn').addEventListener('click', () => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const textToSave = document.getElementById('ocr-text-output').value; + const blob = new Blob([textToSave], { type: 'text/plain' }); + downloadFile(blob, 'ocr-text.txt'); + }); + + } catch (e) { + console.error(e); + showAlert('OCR Error', 'An error occurred during the OCR process. The worker may have failed to load. Please try again.'); + document.getElementById('ocr-options').classList.remove('hidden'); + document.getElementById('ocr-progress').classList.add('hidden'); + } +} + + +/** + * Sets up the UI and event listeners for the OCR tool. + */ +export function setupOcrTool() { + const langSearch = document.getElementById('lang-search'); + const langList = document.getElementById('lang-list'); + const selectedLangsDisplay = document.getElementById('selected-langs-display'); + const processBtn = document.getElementById('process-btn'); + + langSearch.addEventListener('input', () => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const searchTerm = langSearch.value.toLowerCase(); + langList.querySelectorAll('label').forEach(label => { + label.style.display = label.textContent.toLowerCase().includes(searchTerm) ? '' : 'none'; + }); + }); + + // Update the display of selected languages + langList.addEventListener('change', () => { + const selected = Array.from(langList.querySelectorAll('.lang-checkbox:checked')) + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + .map(cb => tesseractLanguages[cb.value]); + selectedLangsDisplay.textContent = selected.length > 0 ? selected.join(', ') : 'None'; + // @ts-expect-error TS(2339) FIXME: Property 'disabled' does not exist on type 'HTMLEl... Remove this comment to see the full error message + processBtn.disabled = selected.length === 0; + }); + + // Attach the main OCR function to the process button + processBtn.addEventListener('click', runOCR); +} \ No newline at end of file diff --git a/src/js/logic/organize.ts b/src/js/logic/organize.ts new file mode 100644 index 0000000..b5b341f --- /dev/null +++ b/src/js/logic/organize.ts @@ -0,0 +1,27 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function organize() { + showLoader('Saving changes...'); + try { + const newPdf = await PDFLibDocument.create(); + const pageContainer = document.getElementById('page-organizer'); + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + const pageIndices = Array.from(pageContainer.children).map(child => parseInt(child.dataset.pageIndex)); + + const copiedPages = await newPdf.copyPages(state.pdfDoc, pageIndices); + copiedPages.forEach((page: any) => newPdf.addPage(page)); + + const newPdfBytes = await newPdf.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'organized.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not save the changes.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/page-dimensions.ts b/src/js/logic/page-dimensions.ts new file mode 100644 index 0000000..c9e0470 --- /dev/null +++ b/src/js/logic/page-dimensions.ts @@ -0,0 +1,80 @@ +import { state } from '../state.js'; +import { getStandardPageName, convertPoints } from '../utils/helpers.js'; + +let analyzedPagesData: any = []; // Store raw data to avoid re-analyzing + +/** + * Renders the dimensions table based on the stored data and selected unit. + * @param {string} unit The unit to display dimensions in ('pt', 'in', 'mm', 'px'). + */ +function renderTable(unit: any) { + const tableBody = document.getElementById('dimensions-table-body'); + if (!tableBody) return; + + tableBody.textContent = ''; // Clear the table body safely + + analyzedPagesData.forEach(pageData => { + const width = convertPoints(pageData.width, unit); + const height = convertPoints(pageData.height, unit); + + const row = document.createElement('tr'); + + // Create and append each cell safely using textContent + const pageNumCell = document.createElement('td'); + pageNumCell.className = 'px-4 py-3 text-white'; + pageNumCell.textContent = pageData.pageNum; + + const dimensionsCell = document.createElement('td'); + dimensionsCell.className = 'px-4 py-3 text-gray-300'; + dimensionsCell.textContent = `${width} x ${height} ${unit}`; + + const sizeCell = document.createElement('td'); + sizeCell.className = 'px-4 py-3 text-gray-300'; + sizeCell.textContent = pageData.standardSize; + + const orientationCell = document.createElement('td'); + orientationCell.className = 'px-4 py-3 text-gray-300'; + orientationCell.textContent = pageData.orientation; + + row.append(pageNumCell, dimensionsCell, sizeCell, orientationCell); + tableBody.appendChild(row); + }); +} + +/** + * Main function to analyze the PDF and display dimensions. + * This is called once after the file is loaded. + */ +export function analyzeAndDisplayDimensions() { + if (!state.pdfDoc) return; + + analyzedPagesData = []; // Reset stored data + const pages = state.pdfDoc.getPages(); + + pages.forEach((page: any, index: any) => { + const { width, height } = page.getSize(); + analyzedPagesData.push({ + pageNum: index + 1, + width, // Store raw width in points + height, // Store raw height in points + orientation: width > height ? 'Landscape' : 'Portrait', + standardSize: getStandardPageName(width, height), + }); + }); + + const resultsContainer = document.getElementById('dimensions-results'); + const unitsSelect = document.getElementById('units-select'); + + // Initial render with default unit (points) + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + renderTable(unitsSelect.value); + + // Show the results table + resultsContainer.classList.remove('hidden'); + + // Add event listener to handle unit changes + unitsSelect.addEventListener('change', (e) => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'EventTarg... Remove this comment to see the full error message + renderTable(e.target.value); + }); +} \ No newline at end of file diff --git a/src/js/logic/pdf-to-bmp.ts b/src/js/logic/pdf-to-bmp.ts new file mode 100644 index 0000000..1b2c4d9 --- /dev/null +++ b/src/js/logic/pdf-to-bmp.ts @@ -0,0 +1,93 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import JSZip from 'jszip'; + +/** + * Creates a BMP file buffer from raw pixel data (ImageData). + * This function is self-contained and has no external dependencies. + * @param {ImageData} imageData The pixel data from a canvas context. + * @returns {ArrayBuffer} The complete BMP file as an ArrayBuffer. + */ +function encodeBMP(imageData: any) { + const { width, height, data } = imageData; + const stride = Math.floor((24 * width + 31) / 32) * 4; // Row size must be a multiple of 4 bytes + const fileSize = stride * height + 54; // 54 byte header + const buffer = new ArrayBuffer(fileSize); + const view = new DataView(buffer); + + // BMP File Header (14 bytes) + view.setUint16(0, 0x4D42, true); // 'BM' + view.setUint32(2, fileSize, true); + view.setUint32(10, 54, true); // Offset to pixel data + + // DIB Header (BITMAPINFOHEADER) (40 bytes) + view.setUint32(14, 40, true); // DIB header size + view.setUint32(18, width, true); + view.setUint32(22, -height, true); // Negative height for top-down scanline order + view.setUint16(26, 1, true); // Color planes + view.setUint16(28, 24, true); // Bits per pixel + view.setUint32(30, 0, true); // No compression + view.setUint32(34, stride * height, true); // Image size + view.setUint32(38, 2835, true); // Horizontal resolution (72 DPI) + view.setUint32(42, 2835, true); // Vertical resolution (72 DPI) + + // Pixel Data + let offset = 54; + for (let y = 0; y < height; y++) { + for (let x = 0; x < width; x++) { + const i = (y * width + x) * 4; + // BMP is BGR, not RGB + view.setUint8(offset++, data[i + 2]); // Blue + view.setUint8(offset++, data[i + 1]); // Green + view.setUint8(offset++, data[i]); // Red + } + // Add padding to make the row a multiple of 4 bytes + for (let p = 0; p < (stride - width * 3); p++) { + view.setUint8(offset++, 0); + } + } + return buffer; +} + + +export async function pdfToBmp() { + showLoader('Converting PDF to BMP images...'); + try { + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + const zip = new JSZip(); + + for (let i = 1; i <= pdf.numPages; i++) { + showLoader(`Processing page ${i} of ${pdf.numPages}...`); + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 1.5 }); + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.height = viewport.height; + canvas.width = viewport.width; + + // Render the PDF page directly to the canvas + await page.render({ canvasContext: context, viewport: viewport }).promise; + + // Get the raw pixel data from this canvas + const imageData = context.getImageData(0, 0, canvas.width, canvas.height); + + // Use our new self-contained function to create the BMP file + const bmpBuffer = encodeBMP(imageData); + + // Add the generated BMP file to the zip archive + zip.file(`page_${i}.bmp`, bmpBuffer); + } + + showLoader('Compressing files into a ZIP...'); + const zipBlob = await zip.generateAsync({ type: "blob" }); + downloadFile(zipBlob, 'converted_bmp_images.zip'); + + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert PDF to BMP. The file might be corrupted.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/pdf-to-greyscale.ts b/src/js/logic/pdf-to-greyscale.ts new file mode 100644 index 0000000..fb7b6c7 --- /dev/null +++ b/src/js/logic/pdf-to-greyscale.ts @@ -0,0 +1,58 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function pdfToGreyscale() { + if (!state.pdfDoc) { + showAlert('Error', 'PDF not loaded.'); + return; + } + showLoader('Converting to greyscale...'); + try { + const newPdfDoc = await PDFLibDocument.create(); + const pdfBytes = await state.pdfDoc.save(); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdfjsDoc = await pdfjsLib.getDocument({ data: pdfBytes }).promise; + + for (let i = 1; i <= pdfjsDoc.numPages; i++) { + const page = await pdfjsDoc.getPage(i); + const viewport = page.getViewport({ scale: 1.5 }); + const canvas = document.createElement('canvas'); + canvas.width = viewport.width; + canvas.height = viewport.height; + const ctx = canvas.getContext('2d'); + + await page.render({ canvasContext: ctx, viewport }).promise; + + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const data = imageData.data; + for (let j = 0; j < data.length; j += 4) { + const avg = (data[j] + data[j + 1] + data[j + 2]) / 3; + data[j] = avg; // red + data[j + 1] = avg; // green + data[j + 2] = avg; // blue + } + ctx.putImageData(imageData, 0, 0); + + const imageBytes = await new Promise(resolve => canvas.toBlob(blob => { + const reader = new FileReader(); + // @ts-expect-error TS(2769) FIXME: No overload matches this call. + reader.onload = () => resolve(new Uint8Array(reader.result)); + reader.readAsArrayBuffer(blob); + }, 'image/png')); + + const image = await newPdfDoc.embedPng(imageBytes as Uint8Array); + const newPage = newPdfDoc.addPage([image.width, image.height]); + newPage.drawImage(image, { x: 0, y: 0, width: image.width, height: image.height }); + } + const newPdfBytes = await newPdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'greyscale.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not convert to greyscale.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/pdf-to-jpg.ts b/src/js/logic/pdf-to-jpg.ts new file mode 100644 index 0000000..20b19c3 --- /dev/null +++ b/src/js/logic/pdf-to-jpg.ts @@ -0,0 +1,35 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import JSZip from 'jszip'; + +export async function pdfToJpg() { + showLoader('Converting to JPG...'); + try { + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + const zip = new JSZip(); + + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2.0 }); + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.height = viewport.height; + canvas.width = viewport.width; + + await page.render({ canvasContext: context, viewport: viewport }).promise; + + const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/jpeg', 0.9)); + zip.file(`page_${i}.jpg`, blob as Blob); + } + + const zipBlob = await zip.generateAsync({ type: "blob" }); + downloadFile(zipBlob, 'converted_images.zip'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert PDF to JPG. The file might be corrupted.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/pdf-to-markdown.ts b/src/js/logic/pdf-to-markdown.ts new file mode 100644 index 0000000..bd79372 --- /dev/null +++ b/src/js/logic/pdf-to-markdown.ts @@ -0,0 +1,31 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; + +export async function pdfToMarkdown() { + showLoader('Converting to Markdown...'); + try { + const file = state.files[0]; + const arrayBuffer = await readFileAsArrayBuffer(file); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise; + let markdown = ''; + + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const content = await page.getTextContent(); + // This is a simple text extraction. For more advanced formatting, more complex logic is needed. + const text = content.items.map((item: any) => item.str).join(' '); + markdown += text + '\n\n'; // Add double newline for paragraph breaks between pages + } + + const blob = new Blob([markdown], { type: 'text/markdown' }); + downloadFile(blob, file.name.replace(/\.pdf$/i, '.md')); + } catch (e) { + console.error(e); + showAlert('Conversion Error', 'Failed to convert PDF. It may be image-based or corrupted.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/pdf-to-png.ts b/src/js/logic/pdf-to-png.ts new file mode 100644 index 0000000..ac38820 --- /dev/null +++ b/src/js/logic/pdf-to-png.ts @@ -0,0 +1,33 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import JSZip from 'jszip'; + + +export async function pdfToPng() { + showLoader('Converting to PNG...'); + try { + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + const zip = new JSZip(); + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2.0 }); + const canvas = document.createElement('canvas'); + canvas.height = viewport.height; + canvas.width = viewport.width; + const context = canvas.getContext('2d'); + await page.render({ canvasContext: context, viewport: viewport }).promise; + const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png')); + zip.file(`page_${i}.png`, blob as Blob); + } + const zipBlob = await zip.generateAsync({ type: "blob" }); + downloadFile(zipBlob, 'converted_pngs.zip'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert PDF to PNG.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/pdf-to-tiff.ts b/src/js/logic/pdf-to-tiff.ts new file mode 100644 index 0000000..2cccdc4 --- /dev/null +++ b/src/js/logic/pdf-to-tiff.ts @@ -0,0 +1,38 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import JSZip from 'jszip'; +import UTIF from 'utif'; +import * as pdfjsLib from "pdfjs-dist"; + +export async function pdfToTiff() { + showLoader('Converting PDF to TIFF...'); + try { + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + const zip = new JSZip(); + + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2.0 }); // Use 2x scale for high quality + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.height = viewport.height; + canvas.width = viewport.width; + + await page.render({ canvasContext: context, viewport: viewport, canvas: canvas }).promise; + const imageData = context.getImageData(0, 0, canvas.width, canvas.height); + const rgba = imageData.data; + const tiffBuffer = UTIF.encodeImage(new Uint8Array(rgba), canvas.width, canvas.height); + + zip.file(`page_${i}.tiff`, tiffBuffer); + } + + const zipBlob = await zip.generateAsync({ type: "blob" }); + downloadFile(zipBlob, 'converted_tiff_images.zip'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert PDF to TIFF. The file might be corrupted.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/pdf-to-webp.ts b/src/js/logic/pdf-to-webp.ts new file mode 100644 index 0000000..1889b58 --- /dev/null +++ b/src/js/logic/pdf-to-webp.ts @@ -0,0 +1,32 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import JSZip from 'jszip'; + +export async function pdfToWebp() { + showLoader('Converting to WebP...'); + try { + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument(await readFileAsArrayBuffer(state.files[0])).promise; + const zip = new JSZip(); + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 2.0 }); + const canvas = document.createElement('canvas'); + canvas.height = viewport.height; + canvas.width = viewport.width; + const context = canvas.getContext('2d'); + await page.render({ canvasContext: context, viewport: viewport }).promise; + const blob = await new Promise(resolve => canvas.toBlob(resolve, 'image/webp', 0.9)); + zip.file(`page_${i}.webp`, blob as Blob); + } + const zipBlob = await zip.generateAsync({ type: "blob" }); + downloadFile(zipBlob, 'converted_webp.zip'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert PDF to WebP.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/pdf-to-zip.ts b/src/js/logic/pdf-to-zip.ts new file mode 100644 index 0000000..b5f15ab --- /dev/null +++ b/src/js/logic/pdf-to-zip.ts @@ -0,0 +1,27 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import JSZip from 'jszip'; + + +export async function pdfToZip() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select one or more PDF files.'); + return; + } + showLoader('Creating ZIP file...'); + try { + const zip = new JSZip(); + for (const file of state.files) { + const fileBuffer = await readFileAsArrayBuffer(file); + zip.file(file.name, fileBuffer as ArrayBuffer); + } + const zipBlob = await zip.generateAsync({ type: 'blob' }); + downloadFile(zipBlob, 'pdfs.zip'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to create ZIP file.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/png-to-pdf.ts b/src/js/logic/png-to-pdf.ts new file mode 100644 index 0000000..c0a70c3 --- /dev/null +++ b/src/js/logic/png-to-pdf.ts @@ -0,0 +1,35 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function pngToPdf() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select at least one PNG file.'); + return; + } + showLoader('Creating PDF from PNGs...'); + try { + const pdfDoc = await PDFLibDocument.create(); + for (const file of state.files) { + const pngBytes = await readFileAsArrayBuffer(file); + const pngImage = await pdfDoc.embedPng(pngBytes as ArrayBuffer); + const page = pdfDoc.addPage([pngImage.width, pngImage.height]); + page.drawImage(pngImage, { + x: 0, + y: 0, + width: pngImage.width, + height: pngImage.height, + }); + } + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'from_pngs.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to create PDF from PNG images. Ensure all files are valid PNGs.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/redact.ts b/src/js/logic/redact.ts new file mode 100644 index 0000000..c76eca1 --- /dev/null +++ b/src/js/logic/redact.ts @@ -0,0 +1,41 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +// @ts-expect-error TS(2339) FIXME: Property 'PDFLib' does not exist on type 'Window &... Remove this comment to see the full error message +const { rgb } = window.PDFLib; + +export async function redact(redactions: any, canvasScale: any) { + showLoader('Applying redactions...'); + try { + const pdfPages = state.pdfDoc.getPages(); + const conversionScale = 1 / canvasScale; + + redactions.forEach((r: any) => { + const page = pdfPages[r.pageIndex]; + const { height: pageHeight } = page.getSize(); + + // Convert canvas coordinates back to PDF coordinates + const pdfX = r.canvasX * conversionScale; + const pdfWidth = r.canvasWidth * conversionScale; + const pdfHeight = r.canvasHeight * conversionScale; + const pdfY = pageHeight - (r.canvasY * conversionScale) - pdfHeight; + + page.drawRectangle({ + x: pdfX, + y: pdfY, + width: pdfWidth, + height: pdfHeight, + color: rgb(0, 0, 0), + }); + }); + + const redactedBytes = await state.pdfDoc.save(); + downloadFile(new Blob([redactedBytes], { type: 'application/pdf' }), 'redacted.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to apply redactions.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/remove-annotations.ts b/src/js/logic/remove-annotations.ts new file mode 100644 index 0000000..db000c4 --- /dev/null +++ b/src/js/logic/remove-annotations.ts @@ -0,0 +1,104 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import { PDFName } from 'pdf-lib'; + +export function setupRemoveAnnotationsTool() { + if (state.pdfDoc) { + document.getElementById('total-pages').textContent = state.pdfDoc.getPageCount(); + } + + const pageScopeRadios = document.querySelectorAll('input[name="page-scope"]'); + const pageRangeWrapper = document.getElementById('page-range-wrapper'); + pageScopeRadios.forEach(radio => { + radio.addEventListener('change', () => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + pageRangeWrapper.classList.toggle('hidden', radio.value !== 'specific'); + }); + }); + + const selectAllCheckbox = document.getElementById('select-all-annotations'); + const allAnnotCheckboxes = document.querySelectorAll('.annot-checkbox'); + selectAllCheckbox.addEventListener('change', () => { + allAnnotCheckboxes.forEach(checkbox => { + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'Element... Remove this comment to see the full error message + checkbox.checked = selectAllCheckbox.checked; + }); + }); +} + +export async function removeAnnotations() { + showLoader('Removing annotations...'); + try { + const totalPages = state.pdfDoc.getPageCount(); + let targetPageIndices = []; + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + const pageScope = document.querySelector('input[name="page-scope"]:checked').value; + if (pageScope === 'all') { + targetPageIndices = Array.from({ length: totalPages }, (_, i) => i); + } else { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const rangeInput = document.getElementById('page-range-input').value; + if (!rangeInput.trim()) throw new Error('Please enter a page range.'); + const ranges = rangeInput.split(','); + for (const range of ranges) { + const trimmedRange = range.trim(); + if (trimmedRange.includes('-')) { + const [start, end] = trimmedRange.split('-').map(Number); + if (isNaN(start) || isNaN(end) || start < 1 || end > totalPages || start > end) continue; + for (let i = start; i <= end; i++) targetPageIndices.push(i - 1); + } else { + const pageNum = Number(trimmedRange); + if (isNaN(pageNum) || pageNum < 1 || pageNum > totalPages) continue; + targetPageIndices.push(pageNum - 1); + } + } + targetPageIndices = [...new Set(targetPageIndices)]; + } + + if (targetPageIndices.length === 0) throw new Error('No valid pages were selected.'); + + const typesToRemove = new Set( + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + Array.from(document.querySelectorAll('.annot-checkbox:checked')).map(cb => cb.value) + ); + + if (typesToRemove.size === 0) throw new Error('Please select at least one annotation type to remove.'); + + const pages = state.pdfDoc.getPages(); + + for (const pageIndex of targetPageIndices) { + const page = pages[pageIndex]; + const annotRefs = page.node.Annots()?.asArray() || []; + + const annotsToKeep = []; + + for (const ref of annotRefs) { + const annot = state.pdfDoc.context.lookup(ref); + const subtype = annot.get(PDFName.of('Subtype'))?.toString().substring(1); + + // If the subtype is NOT in the list to remove, add it to our new array + if (!subtype || !typesToRemove.has(subtype)) { + annotsToKeep.push(ref); + } + } + + if (annotsToKeep.length > 0) { + const newAnnotsArray = state.pdfDoc.context.obj(annotsToKeep); + page.node.set(PDFName.of('Annots'), newAnnotsArray); + } else { + page.node.delete(PDFName.of('Annots')); + } + } + + const newPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'annotations-removed.pdf'); + + } catch (e) { + console.error(e); + showAlert('Error', e.message || 'Could not remove annotations. Please check your page range.'); + } finally { + hideLoader(); + } +} diff --git a/src/js/logic/remove-metadata.ts b/src/js/logic/remove-metadata.ts new file mode 100644 index 0000000..5302662 --- /dev/null +++ b/src/js/logic/remove-metadata.ts @@ -0,0 +1,32 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +export async function removeMetadata() { + showLoader('Removing all metadata...'); + try { + const infoDict = state.pdfDoc.getInfoDict(); + + const allKeys = infoDict.keys(); + allKeys.forEach((key: any) => { + infoDict.delete(key); + }); + + state.pdfDoc.setTitle(''); + state.pdfDoc.setAuthor(''); + state.pdfDoc.setSubject(''); + state.pdfDoc.setKeywords([]); + state.pdfDoc.setCreator(''); + state.pdfDoc.setProducer(''); + + const newPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'metadata-removed.pdf'); + + } catch (e) { + console.error(e); + showAlert('Error', 'An error occurred while trying to remove metadata.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/reverse-pages.ts b/src/js/logic/reverse-pages.ts new file mode 100644 index 0000000..1c333bb --- /dev/null +++ b/src/js/logic/reverse-pages.ts @@ -0,0 +1,26 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function reversePages() { + if (!state.pdfDoc) { showAlert('Error', 'PDF not loaded.'); return; } + showLoader('Reversing page order...'); + try { + const newPdf = await PDFLibDocument.create(); + const pageCount = state.pdfDoc.getPageCount(); + const reversedIndices = Array.from({ length: pageCount }, (_, i) => pageCount - 1 - i); + + const copiedPages = await newPdf.copyPages(state.pdfDoc, reversedIndices); + copiedPages.forEach((page: any) => newPdf.addPage(page)); + + const newPdfBytes = await newPdf.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'reversed.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not reverse the PDF pages.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/rotate.ts b/src/js/logic/rotate.ts new file mode 100644 index 0000000..696873e --- /dev/null +++ b/src/js/logic/rotate.ts @@ -0,0 +1,30 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { degrees } from 'pdf-lib'; + +export async function rotate() { + showLoader('Applying rotations...'); + try { + const pages = state.pdfDoc.getPages(); + document.querySelectorAll('.page-rotator-item').forEach(item => { + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + const pageIndex = parseInt(item.dataset.pageIndex); + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + const rotation = parseInt(item.dataset.rotation || '0'); + if (rotation !== 0) { + const currentRotation = pages[pageIndex].getRotation().angle; + pages[pageIndex].setRotation(degrees(currentRotation + rotation)); + } + }); + + const rotatedPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([rotatedPdfBytes], { type: 'application/pdf' }), 'rotated.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Could not apply rotations.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/scan-to-pdf.ts b/src/js/logic/scan-to-pdf.ts new file mode 100644 index 0000000..db132dc --- /dev/null +++ b/src/js/logic/scan-to-pdf.ts @@ -0,0 +1,4 @@ +// This is essentially the same as image-to-pdf. +import { imageToPdf } from './image-to-pdf.js'; + +export const scanToPdf = imageToPdf; \ No newline at end of file diff --git a/src/js/logic/sign-pdf.ts b/src/js/logic/sign-pdf.ts new file mode 100644 index 0000000..048f708 --- /dev/null +++ b/src/js/logic/sign-pdf.ts @@ -0,0 +1,416 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import html2canvas from 'html2canvas'; + +const signState = { + pdf: null, canvas: null, context: null, pageRendering: false, + currentPageNum: 1, scale: 1.0, + pageSnapshot: null, + drawCanvas: null, drawContext: null, isDrawing: false, + savedSignatures: [], placedSignatures: [], activeSignature: null, + interactionMode: 'none', + draggedSigId: null, + dragOffsetX: 0, dragOffsetY: 0, + hoveredSigId: null, + resizeHandle: null, +}; + + +async function renderPage(num: any) { + signState.pageRendering = true; + const page = await signState.pdf.getPage(num); + const viewport = page.getViewport({ scale: signState.scale }); + signState.canvas.height = viewport.height; + signState.canvas.width = viewport.width; + await page.render({ canvasContext: signState.context, viewport }).promise; + + signState.pageSnapshot = signState.context.getImageData(0, 0, signState.canvas.width, signState.canvas.height); + + drawSignatures(); + + signState.pageRendering = false; + document.getElementById('current-page-display-sign').textContent = num; +} + +function drawSignatures() { + if (!signState.pageSnapshot) return; + signState.context.putImageData(signState.pageSnapshot, 0, 0); + + signState.placedSignatures + .filter(sig => sig.pageIndex === signState.currentPageNum - 1) + .forEach(sig => { + signState.context.drawImage(sig.image, sig.x, sig.y, sig.width, sig.height); + + if (signState.hoveredSigId === sig.id || signState.draggedSigId === sig.id) { + signState.context.strokeStyle = '#4f46e5'; + signState.context.setLineDash([6, 3]); + signState.context.strokeRect(sig.x, sig.y, sig.width, sig.height); + signState.context.setLineDash([]); + + drawResizeHandles(sig); + } + }); +} + + +function drawResizeHandles(sig: any) { + const handleSize = 8; + const halfHandle = handleSize / 2; + const handles = getResizeHandles(sig); + signState.context.fillStyle = '#4f46e5'; + Object.values(handles).forEach(handle => { + signState.context.fillRect(handle.x - halfHandle, handle.y - halfHandle, handleSize, handleSize); + }); +} + + +async function fitToWidth() { + const page = await signState.pdf.getPage(signState.currentPageNum); + const container = document.getElementById('canvas-container-sign'); + signState.scale = container.clientWidth / page.getViewport({ scale: 1.0 }).width; + renderPage(signState.currentPageNum); +} + + +function setupDrawingCanvas() { + signState.drawCanvas = document.getElementById('signature-draw-canvas'); + signState.drawContext = signState.drawCanvas.getContext('2d'); + + const rect = signState.drawCanvas.getBoundingClientRect(); + const dpi = window.devicePixelRatio || 1; + signState.drawCanvas.width = rect.width * dpi; + signState.drawCanvas.height = rect.height * dpi; + signState.drawContext.scale(dpi, dpi); + signState.drawContext.lineWidth = 2; + + const colorPicker = document.getElementById('signature-color'); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + colorPicker.oninput = () => signState.drawContext.strokeStyle = colorPicker.value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + signState.drawContext.strokeStyle = colorPicker.value; + + const start = (e: any) => { + signState.isDrawing = true; + const pos = getMousePos(signState.drawCanvas, e.touches ? e.touches[0] : e); + signState.drawContext.beginPath(); + signState.drawContext.moveTo(pos.x, pos.y); + }; + const draw = (e: any) => { + if (!signState.isDrawing) return; + e.preventDefault(); + const pos = getMousePos(signState.drawCanvas, e.touches ? e.touches[0] : e); + signState.drawContext.lineTo(pos.x, pos.y); + signState.drawContext.stroke(); + }; + const stop = () => signState.isDrawing = false; + + ['mousedown', 'touchstart'].forEach(evt => signState.drawCanvas.addEventListener(evt, start, { passive: false })); + ['mousemove', 'touchmove'].forEach(evt => signState.drawCanvas.addEventListener(evt, draw, { passive: false })); + ['mouseup', 'mouseleave', 'touchend'].forEach(evt => signState.drawCanvas.addEventListener(evt, stop)); +} + +function getMousePos(canvas: any, evt: any) { + const rect = canvas.getBoundingClientRect(); + return { + x: evt.clientX - rect.left, + y: evt.clientY - rect.top + }; +} + +function addSignatureToSaved(imageDataUrl: any) { + const img = new Image(); + img.src = imageDataUrl; + signState.savedSignatures.push(img); + renderSavedSignatures(); +} + +function renderSavedSignatures() { + const container = document.getElementById('saved-signatures-container'); + container.textContent = ''; //change + signState.savedSignatures.forEach((img, index) => { + const wrapper = document.createElement('div'); + wrapper.className = 'saved-signature p-1 bg-white rounded-md cursor-pointer border-2 border-transparent hover:border-indigo-500 h-16'; + img.className = 'h-full w-auto mx-auto'; + wrapper.appendChild(img); + container.appendChild(wrapper); + + wrapper.onclick = () => { + signState.activeSignature = { image: img, index }; + document.querySelectorAll('.saved-signature').forEach(el => el.classList.remove('selected')); + wrapper.classList.add('selected'); + }; + }); +} + +function getResizeHandles(sig: any) { + return { + 'top-left': { x: sig.x, y: sig.y }, + 'top-middle': { x: sig.x + sig.width / 2, y: sig.y }, + 'top-right': { x: sig.x + sig.width, y: sig.y }, + 'middle-left': { x: sig.x, y: sig.y + sig.height / 2 }, + 'middle-right': { x: sig.x + sig.width, y: sig.y + sig.height / 2 }, + 'bottom-left': { x: sig.x, y: sig.y + sig.height }, + 'bottom-middle':{ x: sig.x + sig.width / 2, y: sig.y + sig.height }, + 'bottom-right': { x: sig.x + sig.width, y: sig.y + sig.height }, + }; +} + + +function getHandleAtPos(pos: any, sig: any) { + const handles = getResizeHandles(sig); + const handleSize = 10; + for (const [name, handlePos] of Object.entries(handles)) { + if (Math.abs(pos.x - handlePos.x) < handleSize && Math.abs(pos.y - handlePos.y) < handleSize) { + return name; + } + } + return null; +} + +function setupPlacementListeners() { + const canvas = signState.canvas; + const ghost = document.getElementById('signature-ghost'); + + const mouseMoveHandler = (e: any) => { + if (signState.interactionMode !== 'none') return; + + if (signState.activeSignature) { + ghost.style.backgroundImage = `url('${signState.activeSignature.image.src}')`; + ghost.style.width = '150px'; + ghost.style.height = `${(signState.activeSignature.image.height / signState.activeSignature.image.width) * 150}px`; + ghost.style.left = `${e.clientX + 5}px`; + ghost.style.top = `${e.clientY + 5}px`; + ghost.classList.remove('hidden'); + } + + const pos = getMousePos(canvas, e); + let foundSigId: any = null; + let foundHandle = null; + + signState.placedSignatures.filter(s => s.pageIndex === signState.currentPageNum - 1).reverse().forEach(sig => { + if (foundSigId) return; + const handle = getHandleAtPos(pos, sig); + if (handle) { + foundSigId = sig.id; + foundHandle = handle; + } else if (pos.x >= sig.x && pos.x <= sig.x + sig.width && pos.y >= sig.y && pos.y <= sig.y + sig.height) { + foundSigId = sig.id; + } + }); + + canvas.className = ''; + if (foundHandle) { + if (['top-left', 'bottom-right'].includes(foundHandle)) canvas.classList.add('resize-nwse'); + else if (['top-right', 'bottom-left'].includes(foundHandle)) canvas.classList.add('resize-nesw'); + else if (['top-middle', 'bottom-middle'].includes(foundHandle)) canvas.classList.add('resize-ns'); + else if (['middle-left', 'middle-right'].includes(foundHandle)) canvas.classList.add('resize-ew'); + } else if (foundSigId) { + canvas.classList.add('movable'); + } + + if (signState.hoveredSigId !== foundSigId) { + signState.hoveredSigId = foundSigId; + drawSignatures(); + } + }; + + canvas.addEventListener('mousemove', mouseMoveHandler); + document.getElementById('canvas-container-sign').addEventListener('mouseleave', () => ghost.classList.add('hidden')); + + const onDragStart = (e: any) => { + const pos = getMousePos(canvas, e.touches ? e.touches[0] : e); + let clickedOnSignature = false; + + signState.placedSignatures.filter(s => s.pageIndex === signState.currentPageNum - 1).reverse().forEach(sig => { + if (clickedOnSignature) return; + const handle = getHandleAtPos(pos, sig); + if (handle) { + signState.interactionMode = 'resize'; + signState.resizeHandle = handle; + signState.draggedSigId = sig.id; + clickedOnSignature = true; + } else if (pos.x >= sig.x && pos.x <= sig.x + sig.width && pos.y >= sig.y && pos.y <= sig.y + sig.height) { + signState.interactionMode = 'drag'; + signState.draggedSigId = sig.id; + signState.dragOffsetX = pos.x - sig.x; + signState.dragOffsetY = pos.y - sig.y; + clickedOnSignature = true; + } + }); + + if (clickedOnSignature) { + ghost.classList.add('hidden'); + } else if (signState.activeSignature) { + const sigWidth = 150; + const sigHeight = (signState.activeSignature.image.height / signState.activeSignature.image.width) * sigWidth; + signState.placedSignatures.push({ + id: Date.now(), image: signState.activeSignature.image, + x: pos.x - sigWidth / 2, y: pos.y - sigHeight / 2, + width: sigWidth, height: sigHeight, pageIndex: signState.currentPageNum - 1, + aspectRatio: sigWidth / sigHeight, + }); + drawSignatures(); + } + }; + + const onDragMove = (e: any) => { + if (signState.interactionMode === 'none') return; + e.preventDefault(); + const pos = getMousePos(canvas, e.touches ? e.touches[0] : e); + const sig = signState.placedSignatures.find(s => s.id === signState.draggedSigId); + if (!sig) return; + + if (signState.interactionMode === 'drag') { + sig.x = pos.x - signState.dragOffsetX; + sig.y = pos.y - signState.dragOffsetY; + } else if (signState.interactionMode === 'resize') { + const originalRight = sig.x + sig.width; + const originalBottom = sig.y + sig.height; + + if (signState.resizeHandle.includes('right')) sig.width = Math.max(20, pos.x - sig.x); + if (signState.resizeHandle.includes('bottom')) sig.height = Math.max(20, pos.y - sig.y); + if (signState.resizeHandle.includes('left')) { + sig.width = Math.max(20, originalRight - pos.x); + sig.x = originalRight - sig.width; + } + if (signState.resizeHandle.includes('top')) { + sig.height = Math.max(20, originalBottom - pos.y); + sig.y = originalBottom - sig.height; + } + + if (signState.resizeHandle.includes('left') || signState.resizeHandle.includes('right')) { + sig.height = sig.width / sig.aspectRatio; + } else if (signState.resizeHandle.includes('top') || signState.resizeHandle.includes('bottom')) { + sig.width = sig.height * sig.aspectRatio; + } + } + drawSignatures(); + }; + + const onDragEnd = () => { + signState.interactionMode = 'none'; + signState.draggedSigId = null; + drawSignatures(); + }; + + ['mousedown', 'touchstart'].forEach(evt => canvas.addEventListener(evt, onDragStart, { passive: false })); + ['mousemove', 'touchmove'].forEach(evt => canvas.addEventListener(evt, onDragMove, { passive: false })); + ['mouseup', 'mouseleave', 'touchend'].forEach(evt => canvas.addEventListener(evt, onDragEnd)); +} + +export async function setupSignTool() { + document.getElementById('signature-editor').classList.remove('hidden'); + + signState.canvas = document.getElementById('canvas-sign'); + signState.context = signState.canvas.getContext('2d'); + const pdfData = await state.pdfDoc.save(); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + signState.pdf = await pdfjsLib.getDocument({ data: pdfData }).promise; + document.getElementById('total-pages-display-sign').textContent = signState.pdf.numPages; + + await fitToWidth(); + setupDrawingCanvas(); + setupPlacementListeners(); + + document.getElementById('prev-page-sign').onclick = () => { if (signState.currentPageNum > 1) { signState.currentPageNum--; renderPage(signState.currentPageNum); } }; + document.getElementById('next-page-sign').onclick = () => { if (signState.currentPageNum < signState.pdf.numPages) { signState.currentPageNum++; renderPage(signState.currentPageNum); } }; + document.getElementById('zoom-in-btn').onclick = () => { signState.scale += 0.25; renderPage(signState.currentPageNum); }; + document.getElementById('zoom-out-btn').onclick = () => { signState.scale = Math.max(0.25, signState.scale - 0.25); renderPage(signState.currentPageNum); }; + document.getElementById('fit-width-btn').onclick = fitToWidth; + document.getElementById('undo-btn').onclick = () => { signState.placedSignatures.pop(); drawSignatures(); }; + + const tabs = ['draw', 'type', 'upload']; + const tabButtons = tabs.map(t => document.getElementById(`${t}-tab-btn`)); + const tabPanels = tabs.map(t => document.getElementById(`${t}-panel`)); + tabButtons.forEach((button, index) => { + button.onclick = () => { + tabPanels.forEach(panel => panel.classList.add('hidden')); + tabButtons.forEach(btn => { + btn.classList.remove('border-indigo-500', 'text-white'); + btn.classList.add('border-transparent', 'text-gray-400'); + }); + tabPanels[index].classList.remove('hidden'); + button.classList.add('border-indigo-500', 'text-white'); + button.classList.remove('border-transparent', 'text-gray-400'); + }; + }); + + document.getElementById('clear-draw-btn').onclick = () => signState.drawContext.clearRect(0, 0, signState.drawCanvas.width, signState.drawCanvas.height); + document.getElementById('save-draw-btn').onclick = () => { addSignatureToSaved(signState.drawCanvas.toDataURL()); signState.drawContext.clearRect(0, 0, signState.drawCanvas.width, signState.drawCanvas.height); }; + + const textInput = document.getElementById('signature-text-input'); + const fontPreview = document.getElementById('font-preview'); + const fontFamilySelect = document.getElementById('font-family-select'); + const fontSizeSlider = document.getElementById('font-size-slider'); + const fontSizeValue = document.getElementById('font-size-value'); + const fontColorPicker = document.getElementById('font-color-picker'); + + const updateFontPreview = () => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + fontPreview.textContent = textInput.value || 'Your Name'; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + fontPreview.style.fontFamily = fontFamilySelect.value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + fontPreview.style.fontSize = `${fontSizeSlider.value}px`; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + fontPreview.style.color = fontColorPicker.value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + fontSizeValue.textContent = fontSizeSlider.value; + }; + + [textInput, fontFamilySelect, fontSizeSlider, fontColorPicker].forEach(el => el.addEventListener('input', updateFontPreview)); + updateFontPreview(); + + document.getElementById('save-type-btn').onclick = async () => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + if (!textInput.value) return; + const canvas = await html2canvas(fontPreview, { backgroundColor: null, scale: 2 }); + addSignatureToSaved(canvas.toDataURL()); + }; + + document.getElementById('signature-upload-input').onchange = (e) => { + // @ts-expect-error TS(2339) FIXME: Property 'files' does not exist on type 'EventTarg... Remove this comment to see the full error message + const file = e.target.files[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = (event) => addSignatureToSaved(event.target.result); + reader.readAsDataURL(file); + }; +} + +export async function applyAndSaveSignatures() { + if (signState.placedSignatures.length === 0) { + showAlert('No Signatures Placed', 'Please place at least one signature.'); + return; + } + showLoader('Applying signatures...'); + try { + const pages = state.pdfDoc.getPages(); + for (const sig of signState.placedSignatures) { + const page = pages[sig.pageIndex]; + const originalPageSize = page.getSize(); + const pngBytes = await fetch(sig.image.src).then(res => res.arrayBuffer()); + const pngImage = await state.pdfDoc.embedPng(pngBytes); + + const renderedPage = await signState.pdf.getPage(sig.pageIndex + 1); + const renderedViewport = renderedPage.getViewport({ scale: signState.scale }); + const scaleRatio = originalPageSize.width / renderedViewport.width; + + page.drawImage(pngImage, { + x: sig.x * scaleRatio, + y: originalPageSize.height - (sig.y * scaleRatio) - (sig.height * scaleRatio), + width: sig.width * scaleRatio, + height: sig.height * scaleRatio, + }); + } + + const newPdfBytes = await state.pdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'signed.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to apply signatures.'); + } finally { + hideLoader(); + } +} diff --git a/src/js/logic/split-in-half.ts b/src/js/logic/split-in-half.ts new file mode 100644 index 0000000..3c7e998 --- /dev/null +++ b/src/js/logic/split-in-half.ts @@ -0,0 +1,53 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument, rgb } from 'pdf-lib'; + +export async function splitInHalf() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const splitType = document.getElementById('split-type').value; + if (!state.pdfDoc) { + showAlert('Error', 'No PDF document is loaded.'); + return; + } + showLoader('Splitting PDF pages...'); + try { + const newPdfDoc = await PDFLibDocument.create(); + const pages = state.pdfDoc.getPages(); + + for (let i = 0; i < pages.length; i++) { + const originalPage = pages[i]; + const { width, height } = originalPage.getSize(); + const whiteColor = rgb(1, 1, 1); // For masking + + showLoader(`Processing page ${i + 1} of ${pages.length}...`); + + // Copy the page twice for all split types + const [page1] = await newPdfDoc.copyPages(state.pdfDoc, [i]); + const [page2] = await newPdfDoc.copyPages(state.pdfDoc, [i]); + + switch (splitType) { + case 'vertical': + page1.setCropBox(0, 0, width / 2, height); + page2.setCropBox(width / 2, 0, width / 2, height); + break; + case 'horizontal': + page1.setCropBox(0, height / 2, width, height / 2); // Top half + page2.setCropBox(0, 0, width, height / 2); // Bottom half + break; + } + newPdfDoc.addPage(page1); + newPdfDoc.addPage(page2); + } + + const newPdfBytes = await newPdfDoc.save(); + downloadFile(new Blob([newPdfBytes], { type: 'application/pdf' }), 'split-half.pdf'); + + } catch (e) { + console.error(e); + showAlert('Error', 'An error occurred while splitting the PDF.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/split.ts b/src/js/logic/split.ts new file mode 100644 index 0000000..0fbf64a --- /dev/null +++ b/src/js/logic/split.ts @@ -0,0 +1,213 @@ + +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; +import JSZip from 'jszip'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +// Track if visual selector has been rendered to avoid duplicates +let visualSelectorRendered = false; + + +async function renderVisualSelector() { + if (visualSelectorRendered) return; + + const container = document.getElementById('page-selector-grid'); + if (!container) return; + + visualSelectorRendered = true; + + container.textContent = ''; + + showLoader('Rendering page previews...'); + try { + const pdfData = await state.pdfDoc.save(); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument({ data: pdfData }).promise; + + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 0.4 }); + const canvas = document.createElement('canvas'); + canvas.height = viewport.height; + canvas.width = viewport.width; + await page.render({ canvasContext: canvas.getContext('2d'), viewport: viewport }).promise; + + const wrapper = document.createElement('div'); + wrapper.className = 'page-thumbnail-wrapper p-1 border-2 border-transparent rounded-lg cursor-pointer hover:border-indigo-500'; + // @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'. + wrapper.dataset.pageIndex = i - 1; + + const img = document.createElement('img'); + img.src = canvas.toDataURL(); + img.className = 'rounded-md w-full h-auto'; + const p = document.createElement('p'); + p.className = 'text-center text-xs mt-1 text-gray-300'; + p.textContent = `Page ${i}`; + wrapper.append(img, p); + + const handleSelection = (e: any) => { + e.preventDefault(); + e.stopPropagation(); + + const isSelected = wrapper.classList.contains('selected'); + + if (isSelected) { + wrapper.classList.remove('selected', 'border-indigo-500'); + wrapper.classList.add('border-transparent'); + } else { + wrapper.classList.add('selected', 'border-indigo-500'); + wrapper.classList.remove('border-transparent'); + } + }; + + wrapper.addEventListener('click', handleSelection); + wrapper.addEventListener('touchend', handleSelection); + + wrapper.addEventListener('touchstart', (e) => { + e.preventDefault(); + }); + container.appendChild(wrapper); + } + } catch (error) { + console.error('Error rendering visual selector:', error); + showAlert('Error', 'Failed to render page previews.'); + // 4. ADDED: Reset the flag on error so the user can try again. + visualSelectorRendered = false; + } finally { + hideLoader(); + } +} + + +export function setupSplitTool() { + const splitModeSelect = document.getElementById('split-mode'); + const rangePanel = document.getElementById('range-panel'); + const visualPanel = document.getElementById('visual-select-panel'); + const evenOddPanel = document.getElementById('even-odd-panel'); + const zipOptionWrapper = document.getElementById('zip-option-wrapper'); + const allPagesPanel = document.getElementById('all-pages-panel'); + + if (!splitModeSelect) return; + + splitModeSelect.addEventListener('change', (e) => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'EventTarg... Remove this comment to see the full error message + const mode = e.target.value; + + if (mode !== 'visual') { + visualSelectorRendered = false; + const container = document.getElementById('page-selector-grid'); + if (container) container.innerHTML = ''; + } + + rangePanel.classList.add('hidden'); + visualPanel.classList.add('hidden'); + evenOddPanel.classList.add('hidden'); + allPagesPanel.classList.add('hidden'); + zipOptionWrapper.classList.add('hidden'); + + if (mode === 'range') { + rangePanel.classList.remove('hidden'); + zipOptionWrapper.classList.remove('hidden'); + } else if (mode === 'visual') { + visualPanel.classList.remove('hidden'); + zipOptionWrapper.classList.remove('hidden'); + renderVisualSelector(); + } else if (mode === 'even-odd') { + evenOddPanel.classList.remove('hidden'); + } else if (mode === 'all') { + allPagesPanel.classList.remove('hidden'); + } + }); +} + + +export async function split() { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const splitMode = document.getElementById('split-mode').value; + // @ts-expect-error TS(2339) FIXME: Property 'checked' does not exist on type 'HTMLEle... Remove this comment to see the full error message + const downloadAsZip = document.getElementById('download-as-zip')?.checked || false; + + showLoader('Splitting PDF...'); + + try { + const totalPages = state.pdfDoc.getPageCount(); + let indicesToExtract: any = []; + + switch (splitMode) { + case 'range': + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const pageRangeInput = document.getElementById('page-range').value; + if (!pageRangeInput) throw new Error('Please enter a page range.'); + const ranges = pageRangeInput.split(','); + for (const range of ranges) { + const trimmedRange = range.trim(); + if (trimmedRange.includes('-')) { + const [start, end] = trimmedRange.split('-').map(Number); + if (isNaN(start) || isNaN(end) || start < 1 || end > totalPages || start > end) continue; + for (let i = start; i <= end; i++) indicesToExtract.push(i - 1); + } else { + const pageNum = Number(trimmedRange); + if (isNaN(pageNum) || pageNum < 1 || pageNum > totalPages) continue; + indicesToExtract.push(pageNum - 1); + } + } + break; + + case 'even-odd': + const choiceElement = document.querySelector('input[name="even-odd-choice"]:checked'); + if (!choiceElement) throw new Error('Please select even or odd pages.'); + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'Element'. + const choice = choiceElement.value; + for (let i = 0; i < totalPages; i++) { + if (choice === 'even' && (i + 1) % 2 === 0) indicesToExtract.push(i); + if (choice === 'odd' && (i + 1) % 2 !== 0) indicesToExtract.push(i); + } + break; + case 'all': + indicesToExtract = Array.from({ length: totalPages }, (_, i) => i); + break; + case 'visual': + indicesToExtract = Array.from(document.querySelectorAll('.page-thumbnail-wrapper.selected')) + // @ts-expect-error TS(2339) FIXME: Property 'dataset' does not exist on type 'Element... Remove this comment to see the full error message + .map(el => parseInt(el.dataset.pageIndex)); + break; + } + + const uniqueIndices = [...new Set(indicesToExtract)]; + if (uniqueIndices.length === 0) { + throw new Error('No pages were selected for splitting.'); + } + + if (splitMode === 'all' || (['range', 'visual'].includes(splitMode) && downloadAsZip)) { + showLoader('Creating ZIP file...'); + const zip = new JSZip(); + for (const index of uniqueIndices) { + const newPdf = await PDFLibDocument.create(); + const [copiedPage] = await newPdf.copyPages(state.pdfDoc, [index as number]); + newPdf.addPage(copiedPage); + const pdfBytes = await newPdf.save(); + // @ts-expect-error TS(2365) FIXME: Operator '+' cannot be applied to types 'unknown' ... Remove this comment to see the full error message + zip.file(`page-${index + 1}.pdf`, pdfBytes); + } + const zipBlob = await zip.generateAsync({ type: 'blob' }); + downloadFile(zipBlob, 'split-pages.zip'); + } else { + const newPdf = await PDFLibDocument.create(); + const copiedPages = await newPdf.copyPages(state.pdfDoc, uniqueIndices as number[]); + copiedPages.forEach((page: any) => newPdf.addPage(page)); + const pdfBytes = await newPdf.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'split-document.pdf'); + } + + if (splitMode === 'visual') { + visualSelectorRendered = false; + } + } catch (e) { + console.error(e); + showAlert('Error', e.message || 'Failed to split PDF. Please check your selection.'); + } finally { + hideLoader(); + } +} diff --git a/src/js/logic/svg-to-pdf.ts b/src/js/logic/svg-to-pdf.ts new file mode 100644 index 0000000..76f9941 --- /dev/null +++ b/src/js/logic/svg-to-pdf.ts @@ -0,0 +1,55 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +async function convertImageToPngBytes(file: any) { + return new Promise((resolve, reject) => { + const img = new Image(); + const reader = new FileReader(); + + reader.onload = (e) => { + img.onload = async () => { + const canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + const pngBlob = await new Promise(res => canvas.toBlob(res, 'image/png')); + // @ts-expect-error TS(2339) FIXME: Property 'arrayBuffer' does not exist on type 'unk... Remove this comment to see the full error message + const pngBytes = await pngBlob.arrayBuffer(); + resolve(pngBytes); + }; + img.onerror = () => reject(new Error('Failed to load image.')); + // @ts-expect-error TS(2322) FIXME: Type 'string | ArrayBuffer' is not assignable to t... Remove this comment to see the full error message + img.src = e.target.result; + }; + reader.onerror = () => reject(new Error('Failed to read file.')); + reader.readAsDataURL(file); + }); +} + +export async function svgToPdf() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select at least one SVG file.'); + return; + } + showLoader('Converting SVG to PDF...'); + try { + const pdfDoc = await PDFLibDocument.create(); + for (const file of state.files) { + const pngBytes = await convertImageToPngBytes(file); + const pngImage = await pdfDoc.embedPng(pngBytes as ArrayBuffer); + const page = pdfDoc.addPage([pngImage.width, pngImage.height]); + page.drawImage(pngImage, { x: 0, y: 0, width: pngImage.width, height: pngImage.height }); + } + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'from_svgs.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert SVG to PDF. One of the files may be invalid.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/tiff-to-pdf.ts b/src/js/logic/tiff-to-pdf.ts new file mode 100644 index 0000000..c2cd5e6 --- /dev/null +++ b/src/js/logic/tiff-to-pdf.ts @@ -0,0 +1,82 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; +import { decode } from 'tiff'; + +export async function tiffToPdf() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select at least one TIFF file.'); + return; + } + showLoader('Converting TIFF to PDF...'); + try { + const pdfDoc = await PDFLibDocument.create(); + for (const file of state.files) { + const tiffBytes = await readFileAsArrayBuffer(file); + const ifds = decode(tiffBytes as any); + + for (const ifd of ifds) { + const canvas = document.createElement('canvas'); + canvas.width = ifd.width; + canvas.height = ifd.height; + const ctx = canvas.getContext('2d'); + + if (!ctx) { + throw new Error('Failed to get canvas context'); + } + + const imageData = ctx.createImageData(ifd.width, ifd.height); + const pixels = imageData.data; + + // Calculate samples per pixel from data length + const totalPixels = ifd.width * ifd.height; + const samplesPerPixel = ifd.data.length / totalPixels; + + // Convert TIFF data to RGBA + for (let i = 0; i < totalPixels; i++) { + const dstIndex = i * 4; + + if (samplesPerPixel === 1) { + // Grayscale + const gray = ifd.data[i]; + pixels[dstIndex] = gray; + pixels[dstIndex + 1] = gray; + pixels[dstIndex + 2] = gray; + pixels[dstIndex + 3] = 255; + } else if (samplesPerPixel === 3) { + // RGB + const srcIndex = i * 3; + pixels[dstIndex] = ifd.data[srcIndex]; + pixels[dstIndex + 1] = ifd.data[srcIndex + 1]; + pixels[dstIndex + 2] = ifd.data[srcIndex + 2]; + pixels[dstIndex + 3] = 255; + } else if (samplesPerPixel === 4) { + // RGBA + const srcIndex = i * 4; + pixels[dstIndex] = ifd.data[srcIndex]; + pixels[dstIndex + 1] = ifd.data[srcIndex + 1]; + pixels[dstIndex + 2] = ifd.data[srcIndex + 2]; + pixels[dstIndex + 3] = ifd.data[srcIndex + 3]; + } + } + + ctx.putImageData(imageData, 0, 0); + + const pngBlob = await new Promise((res) => canvas.toBlob(res!, 'image/png')); + const pngBytes = await pngBlob.arrayBuffer(); + + const pngImage = await pdfDoc.embedPng(pngBytes); + const page = pdfDoc.addPage([pngImage.width, pngImage.height]); + page.drawImage(pngImage, { x: 0, y: 0, width: pngImage.width, height: pngImage.height }); + } + } + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'from_tiff.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert TIFF to PDF. One of the files may be invalid or corrupted.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/txt-to-pdf.ts b/src/js/logic/txt-to-pdf.ts new file mode 100644 index 0000000..f83f9d7 --- /dev/null +++ b/src/js/logic/txt-to-pdf.ts @@ -0,0 +1,74 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, hexToRgb } from '../utils/helpers.js'; + +import { PDFDocument as PDFLibDocument, rgb, StandardFonts, PageSizes } from 'pdf-lib'; + +export async function txtToPdf() { + showLoader('Creating PDF...'); + try { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const text = document.getElementById('text-input').value; + if (!text.trim()) { + showAlert('Input Required', 'Please enter some text to convert.'); + hideLoader(); + return; + } + + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const fontFamilyKey = document.getElementById('font-family').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const fontSize = parseInt(document.getElementById('font-size').value) || 12; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const pageSizeKey = document.getElementById('page-size').value; + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const colorHex = document.getElementById('text-color').value; + const textColor = hexToRgb(colorHex); + + const pdfDoc = await PDFLibDocument.create(); + const font = await pdfDoc.embedFont(StandardFonts[fontFamilyKey]); + const pageSize = PageSizes[pageSizeKey]; + const margin = 72; // 1 inch + + let page = pdfDoc.addPage(pageSize); + let { width, height } = page.getSize(); + const textWidth = width - margin * 2; + const lineHeight = fontSize * 1.3; + let y = height - margin; + + const paragraphs = text.split('\n'); + for (const paragraph of paragraphs) { + const words = paragraph.split(' '); + let currentLine = ''; + for (const word of words) { + const testLine = currentLine.length > 0 ? `${currentLine} ${word}` : word; + if (font.widthOfTextAtSize(testLine, fontSize) <= textWidth) { + currentLine = testLine; + } else { + if (y < margin + lineHeight) { + page = pdfDoc.addPage(pageSize); + y = page.getHeight() - margin; + } + page.drawText(currentLine, { x: margin, y, font, size: fontSize, color: rgb(textColor.r, textColor.g, textColor.b) }); + y -= lineHeight; + currentLine = word; + } + } + if (currentLine.length > 0) { + if (y < margin + lineHeight) { + page = pdfDoc.addPage(pageSize); + y = page.getHeight() - margin; + } + page.drawText(currentLine, { x: margin, y, font, size: fontSize, color: rgb(textColor.r, textColor.g, textColor.b) }); + y -= lineHeight; + } + } + + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'text-document.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to create PDF from text.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/view-metadata.ts b/src/js/logic/view-metadata.ts new file mode 100644 index 0000000..19f305d --- /dev/null +++ b/src/js/logic/view-metadata.ts @@ -0,0 +1,4 @@ +// This tool doesn't have a "process" button. Its logic is handled directly in fileHandler.js after a file is uploaded. +export function viewMetadata() { + console.log(""); +} \ No newline at end of file diff --git a/src/js/logic/webp-to-pdf.ts b/src/js/logic/webp-to-pdf.ts new file mode 100644 index 0000000..01df7d1 --- /dev/null +++ b/src/js/logic/webp-to-pdf.ts @@ -0,0 +1,48 @@ +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { downloadFile, readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; + +import { PDFDocument as PDFLibDocument } from 'pdf-lib'; + +export async function webpToPdf() { + if (state.files.length === 0) { + showAlert('No Files', 'Please select at least one WebP file.'); + return; + } + showLoader('Converting WebP to PDF...'); + try { + const pdfDoc = await PDFLibDocument.create(); + for (const file of state.files) { + const webpBytes = await readFileAsArrayBuffer(file); + // @ts-expect-error TS(2322) FIXME: Type 'unknown' is not assignable to type 'BlobPart... Remove this comment to see the full error message + const imageBitmap = await createImageBitmap(new Blob([webpBytes])); + + const canvas = document.createElement('canvas'); + canvas.width = imageBitmap.width; + canvas.height = imageBitmap.height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(imageBitmap, 0, 0); + + const pngBlob = await new Promise(resolve => canvas.toBlob(resolve, 'image/png')); + // @ts-expect-error TS(2339) FIXME: Property 'arrayBuffer' does not exist on type 'unk... Remove this comment to see the full error message + const pngBytes = await pngBlob.arrayBuffer(); + + // Embed the converted PNG into the PDF + const pngImage = await pdfDoc.embedPng(pngBytes); + const page = pdfDoc.addPage([pngImage.width, pngImage.height]); + page.drawImage(pngImage, { + x: 0, + y: 0, + width: pngImage.width, + height: pngImage.height, + }); + } + const pdfBytes = await pdfDoc.save(); + downloadFile(new Blob([pdfBytes], { type: 'application/pdf' }), 'from_webp.pdf'); + } catch (e) { + console.error(e); + showAlert('Error', 'Failed to convert WebP to PDF. Ensure all files are valid WebP images.'); + } finally { + hideLoader(); + } +} \ No newline at end of file diff --git a/src/js/logic/word-to-pdf.ts b/src/js/logic/word-to-pdf.ts new file mode 100644 index 0000000..cab51dd --- /dev/null +++ b/src/js/logic/word-to-pdf.ts @@ -0,0 +1,131 @@ +// NOTE: This is a work in progress and does not work correctly as of yet +import { showLoader, hideLoader, showAlert } from '../ui.js'; +import { readFileAsArrayBuffer } from '../utils/helpers.js'; +import { state } from '../state.js'; + +export async function wordToPdf() { + const file = state.files[0]; + if (!file) { + showAlert('No File', 'Please upload a .docx file first.'); + return; + } + + showLoader('Preparing preview...'); + + try { + + const mammothOptions = { + // @ts-expect-error TS(2304) FIXME: Cannot find name 'mammoth'. + convertImage: mammoth.images.inline((element: any) => { + return element.read("base64").then((imageBuffer: any) => { + return { + src: `data:${element.contentType};base64,${imageBuffer}` + }; + }); + }) + }; + const arrayBuffer = await readFileAsArrayBuffer(file); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'mammoth'. + const { value: html } = await mammoth.convertToHtml({ arrayBuffer }, mammothOptions); + + // Get references to our modal elements from index.html + const previewModal = document.getElementById('preview-modal'); + const previewContent = document.getElementById('preview-content'); + const downloadBtn = document.getElementById('preview-download-btn'); + const closeBtn = document.getElementById('preview-close-btn'); + + const styledHtml = ` + + ${html} + `; + previewContent.innerHTML = styledHtml; + + const marginDiv = document.createElement('div'); + marginDiv.style.height = '100px'; + previewContent.appendChild(marginDiv); + + const images = previewContent.querySelectorAll('img'); + const imagePromises = Array.from(images).map(img => { + return new Promise((resolve) => { + // @ts-expect-error TS(2794) FIXME: Expected 1 arguments, but got 0. Did you forget to... Remove this comment to see the full error message + if (img.complete) resolve(); + else img.onload = resolve; + }); + }); + await Promise.all(imagePromises); + + + previewModal.classList.remove('hidden'); + hideLoader(); + + const downloadHandler = async () => { + showLoader('Generating High-Quality PDF...'); + + // @ts-expect-error TS(2339) FIXME: Property 'jspdf' does not exist on type 'Window & ... Remove this comment to see the full error message + const { jsPDF } = window.jspdf; + const doc = new jsPDF({ + orientation: 'p', + unit: 'pt', + format: 'letter' + }); + + await doc.html(previewContent, { + callback: function (doc: any) { + const links = previewContent.querySelectorAll('a'); + const pageHeight = doc.internal.pageSize.getHeight(); + const containerRect = previewContent.getBoundingClientRect(); // Get container's position + + links.forEach(link => { + if (!link.href) return; + + const linkRect = link.getBoundingClientRect(); + + // Calculate position relative to the preview container's top-left + const relativeX = linkRect.left - containerRect.left; + const relativeY = linkRect.top - containerRect.top; + + const pageNum = Math.floor(relativeY / pageHeight) + 1; + const yOnPage = relativeY % pageHeight; + + doc.setPage(pageNum); + try { + doc.link(relativeX + 45, yOnPage + 45, linkRect.width, linkRect.height, { url: link.href }); + } catch (e) { + console.warn("Could not add link:", link.href, e); + } + }); + + const outputFileName = `${file.name.replace(/\.[^/.]+$/, "")}.pdf`; + doc.save(outputFileName); + hideLoader(); + }, + autoPaging: 'slice', + x: 45, + y: 45, + width: 522, + windowWidth: previewContent.scrollWidth + }); + }; + + const closeHandler = () => { + previewModal.classList.add('hidden'); + previewContent.innerHTML = ''; + downloadBtn.removeEventListener('click', downloadHandler); + closeBtn.removeEventListener('click', closeHandler); + }; + + downloadBtn.addEventListener('click', downloadHandler); + closeBtn.addEventListener('click', closeHandler); + + } catch (e) { + console.error(e); + hideLoader(); + showAlert('Preview Error', `Could not generate a preview. The file may be corrupt or contain unsupported features. Error: ${e.message}`); + } +} \ No newline at end of file diff --git a/src/js/main.ts b/src/js/main.ts new file mode 100644 index 0000000..fd2a60b --- /dev/null +++ b/src/js/main.ts @@ -0,0 +1,119 @@ +import { categories } from './config/tools.js'; +import { dom, switchView, hideAlert } from './ui.js'; +import { setupToolInterface } from './handlers/toolSelectionHandler.js'; +import { createIcons, icons } from 'lucide'; + +import * as pdfjsLib from 'pdfjs-dist'; + + +const init = () => { + pdfjsLib.GlobalWorkerOptions.workerSrc = new URL( + 'pdfjs-dist/build/pdf.worker.min.mjs', + import.meta.url + ).toString(); + + dom.toolGrid.textContent = ''; + + categories.forEach(category => { + const categoryGroup = document.createElement('div'); + categoryGroup.className = 'category-group col-span-full'; + + const title = document.createElement('h2'); + title.className = 'text-xl font-bold text-indigo-400 mb-4 mt-8 first:mt-0'; + title.textContent = category.name; + + const toolsContainer = document.createElement('div'); + toolsContainer.className = 'grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4 md:gap-6'; + + category.tools.forEach(tool => { + const toolCard = document.createElement('div'); + toolCard.className = 'tool-card bg-gray-800 rounded-xl p-4 cursor-pointer flex flex-col items-center justify-center text-center'; + toolCard.dataset.toolId = tool.id; + + const icon = document.createElement('i'); + icon.className = 'w-10 h-10 mb-3 text-indigo-400'; + icon.setAttribute('data-lucide', tool.icon); + + const toolName = document.createElement('h3'); + toolName.className = 'font-semibold text-white'; + toolName.textContent = tool.name; + + toolCard.append(icon, toolName); + + if (tool.subtitle) { + const toolSubtitle = document.createElement('p'); + toolSubtitle.className = 'text-xs text-gray-400 mt-1 px-2'; + toolSubtitle.textContent = tool.subtitle; + toolCard.appendChild(toolSubtitle); + } + + toolsContainer.appendChild(toolCard); + }); + + categoryGroup.append(title, toolsContainer); + dom.toolGrid.appendChild(categoryGroup); + }); + + const searchBar = document.getElementById('search-bar'); + const categoryGroups = dom.toolGrid.querySelectorAll('.category-group'); + + searchBar.addEventListener('input', () => { + // @ts-expect-error TS(2339) FIXME: Property 'value' does not exist on type 'HTMLEleme... Remove this comment to see the full error message + const searchTerm = searchBar.value.toLowerCase().trim(); + + categoryGroups.forEach(group => { + const toolCards = group.querySelectorAll('.tool-card'); + let visibleToolsInCategory = 0; + + toolCards.forEach(card => { + const toolName = card.querySelector('h3').textContent.toLowerCase(); + const toolSubtitle = card.querySelector('p')?.textContent.toLowerCase() || ''; + const isMatch = toolName.includes(searchTerm) || toolSubtitle.includes(searchTerm); + + card.classList.toggle('hidden', !isMatch); + if (isMatch) { + visibleToolsInCategory++; + } + }); + + group.classList.toggle('hidden', visibleToolsInCategory === 0); + }); + }); + + dom.toolGrid.addEventListener('click', (e) => { + // @ts-expect-error TS(2339) FIXME: Property 'closest' does not exist on type 'EventTa... Remove this comment to see the full error message + const card = e.target.closest('.tool-card'); + if (card) { + const toolId = card.dataset.toolId; + setupToolInterface(toolId); + } + }); + dom.backToGridBtn.addEventListener('click', () => switchView('grid')); + dom.alertOkBtn.addEventListener('click', hideAlert); + + const faqAccordion = document.getElementById('faq-accordion'); + if (faqAccordion) { + faqAccordion.addEventListener('click', (e) => { + // @ts-expect-error TS(2339) FIXME: Property 'closest' does not exist on type 'EventTa... Remove this comment to see the full error message + const questionButton = e.target.closest('.faq-question'); + if (!questionButton) return; + + const faqItem = questionButton.parentElement; + const answer = faqItem.querySelector('.faq-answer'); + + faqItem.classList.toggle('open'); + + if (faqItem.classList.contains('open')) { + answer.style.maxHeight = answer.scrollHeight + 'px'; + } else { + answer.style.maxHeight = '0px'; + } + }); + } + + createIcons({ icons }); + console.log('Please share our tool and share the love!'); +}; + +// --- START THE APP --- +document.addEventListener('DOMContentLoaded', init); \ No newline at end of file diff --git a/src/js/state.ts b/src/js/state.ts new file mode 100644 index 0000000..64c3774 --- /dev/null +++ b/src/js/state.ts @@ -0,0 +1,16 @@ +export const state = { + activeTool: null, + files: [], + pdfDoc: null, + pdfPages: [], + currentPdfUrl: null, +}; + +// Resets the state when switching views or completing an operation. +export function resetState() { + state.activeTool = null; + state.files = []; + state.pdfDoc = null; + state.pdfPages = []; + document.getElementById('tool-content').innerHTML = ''; +} \ No newline at end of file diff --git a/src/js/ui.ts b/src/js/ui.ts new file mode 100644 index 0000000..cd7ae9b --- /dev/null +++ b/src/js/ui.ts @@ -0,0 +1,1698 @@ +// FILE: js/ui.js +import { resetState } from './state.js'; +import { formatBytes } from './utils/helpers.js'; +import { tesseractLanguages } from './config/tesseract-languages.js'; +import { icons, createIcons } from "lucide"; +import Sortable from 'sortablejs'; + +// Centralizing DOM element selection +export const dom = { + gridView: document.getElementById('grid-view'), + toolGrid: document.getElementById('tool-grid'), + toolInterface: document.getElementById('tool-interface'), + toolContent: document.getElementById('tool-content'), + backToGridBtn: document.getElementById('back-to-grid'), + loaderModal: document.getElementById('loader-modal'), + loaderText: document.getElementById('loader-text'), + alertModal: document.getElementById('alert-modal'), + alertTitle: document.getElementById('alert-title'), + alertMessage: document.getElementById('alert-message'), + alertOkBtn: document.getElementById('alert-ok'), + heroSection: document.getElementById('hero-section'), + featuresSection: document.getElementById('features-section'), + toolsHeader: document.getElementById('tools-header'), + dividers: document.querySelectorAll('.section-divider'), + hideSections: document.querySelectorAll('.hide-section'), +}; + +export const showLoader = (text = 'Processing...') => { + dom.loaderText.textContent = text; + dom.loaderModal.classList.remove('hidden'); +}; + +export const hideLoader = () => dom.loaderModal.classList.add('hidden'); + +export const showAlert = (title: any, message: any) => { + dom.alertTitle.textContent = title; + dom.alertMessage.textContent = message; + dom.alertModal.classList.remove('hidden'); +}; + +export const hideAlert = () => dom.alertModal.classList.add('hidden'); + +export const switchView = (view: any) => { + if (view === 'grid') { + dom.gridView.classList.remove('hidden'); + dom.toolInterface.classList.add('hidden'); + // show hero and features and header + dom.heroSection.classList.remove('hidden'); + dom.featuresSection.classList.remove('hidden'); + dom.toolsHeader.classList.remove('hidden'); + // show dividers + dom.dividers.forEach(divider => { + divider.classList.remove('hidden'); + }); + // show hideSections + dom.hideSections.forEach(section => { + section.classList.remove('hidden'); + }); + + resetState(); + } else { + dom.gridView.classList.add('hidden'); + dom.toolInterface.classList.remove('hidden'); + dom.featuresSection.classList.add('hidden'); + dom.heroSection.classList.add('hidden'); + dom.toolsHeader.classList.add('hidden'); + dom.dividers.forEach(divider => { + divider.classList.add('hidden'); + }); + dom.hideSections.forEach(section => { + section.classList.add('hidden'); + }); + + } +}; + +const thumbnailState = { + sortableInstances: {} +}; + + +function initializeOrganizeSortable(containerId: any) { + const container = document.getElementById(containerId); + if (!container) return; + + if (thumbnailState.sortableInstances[containerId]) { + thumbnailState.sortableInstances[containerId].destroy(); + } + + thumbnailState.sortableInstances[containerId] = Sortable.create(container, { + animation: 150, + ghostClass: 'sortable-ghost', + chosenClass: 'sortable-chosen', + dragClass: 'sortable-drag', + filter: '.delete-page-btn', + preventOnFilter: true, + onStart: function(evt: any) { + evt.item.style.opacity = '0.5'; + }, + onEnd: function(evt: any) { + evt.item.style.opacity = '1'; + } + }); +} + + +/** + * Renders page thumbnails for tools like 'Organize' and 'Rotate'. + * @param {string} toolId The ID of the active tool. + * @param {object} pdfDoc The loaded pdf-lib document instance. + */ +export const renderPageThumbnails = async (toolId: any, pdfDoc: any) => { + const containerId = toolId === 'organize' ? 'page-organizer' : 'page-rotator'; + const container = document.getElementById(containerId); + if (!container) return; + + container.innerHTML = ''; + showLoader('Rendering page previews...'); + + const pdfData = await pdfDoc.save(); + // @ts-expect-error TS(2304) FIXME: Cannot find name 'pdfjsLib'. + const pdf = await pdfjsLib.getDocument({ data: pdfData }).promise; + + for (let i = 1; i <= pdf.numPages; i++) { + const page = await pdf.getPage(i); + const viewport = page.getViewport({ scale: 0.5 }); + const canvas = document.createElement('canvas'); + canvas.height = viewport.height; + canvas.width = viewport.width; + const context = canvas.getContext('2d'); + await page.render({ canvasContext: context, viewport: viewport }).promise; + + const wrapper = document.createElement('div'); + wrapper.className = 'page-thumbnail relative group'; + // @ts-expect-error TS(2322) FIXME: Type 'number' is not assignable to type 'string'. + wrapper.dataset.pageIndex = i - 1; + + const imgContainer = document.createElement('div'); + imgContainer.className = 'w-full h-36 bg-gray-900 rounded-lg flex items-center justify-center overflow-hidden border-2 border-gray-600'; + + const img = document.createElement('img'); + img.src = canvas.toDataURL(); + img.className = 'max-w-full max-h-full object-contain'; + + imgContainer.appendChild(img); + + if (toolId === 'organize') { + wrapper.className = 'page-thumbnail relative group'; + wrapper.appendChild(imgContainer); + + const pageNumSpan = document.createElement('span'); + pageNumSpan.className = 'absolute top-1 left-1 bg-gray-900 bg-opacity-75 text-white text-xs rounded-full px-2 py-1'; + pageNumSpan.textContent = i.toString(); + + const deleteBtn = document.createElement('button'); + deleteBtn.className = 'delete-page-btn absolute top-1 right-1 bg-red-600 text-white rounded-full w-6 h-6 flex items-center justify-center'; + deleteBtn.innerHTML = '×'; + deleteBtn.addEventListener('click', (e) => { + (e.currentTarget as HTMLElement).parentElement.remove(); + initializeOrganizeSortable(containerId); + }); + + wrapper.append(pageNumSpan, deleteBtn); + } else if (toolId === 'rotate') { + wrapper.className = 'page-rotator-item flex flex-col items-center gap-2'; + wrapper.dataset.rotation = '0'; + img.classList.add('transition-transform', 'duration-300'); + wrapper.appendChild(imgContainer); + + const controlsDiv = document.createElement('div'); + controlsDiv.className = 'flex items-center justify-center gap-3 w-full'; + + const pageNumSpan = document.createElement('span'); + pageNumSpan.className = 'font-medium text-sm text-white'; + pageNumSpan.textContent = i.toString(); + + const rotateBtn = document.createElement('button'); + rotateBtn.className = 'rotate-btn btn bg-gray-700 hover:bg-gray-600 p-2 rounded-full'; + rotateBtn.title = 'Rotate 90°'; + rotateBtn.innerHTML = ''; + rotateBtn.addEventListener('click', (e) => { + e.stopPropagation(); + const card = (e.currentTarget as HTMLElement).closest('.page-rotator-item') as HTMLElement; + const imgEl = card.querySelector('img'); + let currentRotation = parseInt(card.dataset.rotation); + currentRotation = (currentRotation + 90) % 360; + card.dataset.rotation = currentRotation.toString(); + imgEl.style.transform = `rotate(${currentRotation}deg)`; + }); + + controlsDiv.append(pageNumSpan, rotateBtn); + wrapper.appendChild(controlsDiv); + } + + container.appendChild(wrapper); + createIcons({icons}); + } + + if (toolId === 'organize') { + initializeOrganizeSortable(containerId); + } + + hideLoader(); +}; + +/** + * Renders a list of uploaded files in the specified container. + * @param {HTMLElement} container The DOM element to render the list into. + * @param {File[]} files The array of file objects. + */ +export const renderFileDisplay = (container: any, files: any) => { + container.textContent = ''; + if (files.length > 0) { + files.forEach((file: any) => { + const fileDiv = document.createElement('div'); + fileDiv.className = 'flex items-center justify-between bg-gray-700 p-3 rounded-lg text-sm'; + + const nameSpan = document.createElement('span'); + nameSpan.className = 'truncate font-medium text-gray-200'; + nameSpan.textContent = file.name; + + const sizeSpan = document.createElement('span'); + sizeSpan.className = 'flex-shrink-0 ml-4 text-gray-400'; + sizeSpan.textContent = formatBytes(file.size); + + fileDiv.append(nameSpan, sizeSpan); + container.appendChild(fileDiv); + }); + } +}; + +const createFileInputHTML = (options = {}) => { + // @ts-expect-error TS(2339) FIXME: Property 'multiple' does not exist on type '{}'. + const multiple = options.multiple ? 'multiple' : ''; + // @ts-expect-error TS(2339) FIXME: Property 'accept' does not exist on type '{}'. + const acceptedFiles = options.accept || 'application/pdf'; + // @ts-expect-error TS(2339) FIXME: Property 'showControls' does not exist on type '{}... Remove this comment to see the full error message + const showControls = options.showControls || false; // NEW: Add this parameter + + return ` +
+
+ +

Click to select a file or drag and drop

+

${multiple ? 'PDFs or Images' : 'A single PDF file'}

+

Your files never leave your device.

+
+ +
+ + ${showControls ? ` + + + ` : ''} + `; +}; + +export const toolTemplates = { + merge: () => ` +

Merge PDFs

+

Combine whole files, or select specific pages to merge into a new document.

+ ${createFileInputHTML({ multiple: true, showControls: true })} + + +`, + + split: () => ` +

Split PDF

+

Extract pages from a PDF using various methods.

+ ${createFileInputHTML()} +
+ +`, + encrypt: () => ` +

Encrypt PDF

+

Upload a PDF to create a new, password-protected version.

+ ${createFileInputHTML()} +
+ + + `, + decrypt: () => ` +

Decrypt PDF

+

Upload an encrypted PDF and provide its password to create an unlocked version.

+ ${createFileInputHTML()} +
+ + + `, + organize: () => ` +

Organize PDF

+

Reorder, rotate, or delete pages. Drag and drop pages to reorder them.

+ ${createFileInputHTML()} +
+ + + `, + + rotate: () => ` +

Rotate PDF

+

Rotate all or specific pages in a PDF document.

+ ${createFileInputHTML()} +
+ + + + + `, + + 'add-page-numbers': () => ` +

Add Page Numbers

+

Add customizable page numbers to your PDF file.

+ ${createFileInputHTML()} +
+ + + `, + 'pdf-to-jpg': () => ` +

PDF to JPG

+

Convert each page of a PDF file into a high-quality JPG image.

+ ${createFileInputHTML()} +
+ + `, + 'jpg-to-pdf': () => ` +

JPG to PDF

+

Convert one or more JPG images into a single PDF file.

+ ${createFileInputHTML({ multiple: true, accept: 'image/jpeg', showControls: true })} +
+ + `, + 'scan-to-pdf': () => ` +

Scan to PDF

+

Use your device's camera to scan documents and save them as a PDF. On desktop, this will open a file picker.

+ ${createFileInputHTML({ accept: 'image/*' })} +
+ + `, + + crop: () => ` +

Crop PDF

+

Click and drag to select a crop area on any page. You can set different crop areas for each page.

+ ${createFileInputHTML()} + +`, +compress: () => ` +

Compress PDF

+

Reduce file size by choosing the compression method that best suits your document.

+ ${createFileInputHTML()} +
+ +`, + 'pdf-to-greyscale': () => ` +

PDF to Greyscale

+

Convert all pages of a PDF to greyscale. This is done by rendering each page, applying a filter, and rebuilding the PDF.

+ ${createFileInputHTML()} +
+ + `, + 'pdf-to-zip': () => ` +

Combine PDFs into ZIP

+

Select multiple PDF files to download them together in a single ZIP archive.

+ ${createFileInputHTML({ multiple: true, showControls: true })} +
+ + `, + +'edit-metadata': () => ` +

Edit PDF Metadata

+

Modify the core metadata fields of your PDF. Leave a field blank to clear it.

+ +
+ +
+ Important Note: + This tool pdf-lib library, which may update the Producer, CreationDate, and ModDate fields due to its default behavior on upload. To accurately view a file's final metadata after editing, or just normal viewing, please use our View Metadata tool. +
+
+ + ${createFileInputHTML()} + + + + +`, + + 'remove-metadata': () => ` +

Remove PDF Metadata

+

Completely remove identifying metadata from your PDF.

+ ${createFileInputHTML()} +
+ + `, + flatten: () => ` +

Flatten PDF

+

Make PDF forms and annotations non-editable by flattening them.

+ ${createFileInputHTML()} +
+ + `, + 'pdf-to-png': () => ` +

PDF to PNG

+

Convert each page of a PDF file into a high-quality PNG image.

+ ${createFileInputHTML()} +
+ + `, + 'png-to-pdf': () => ` +

PNG to PDF

+

Convert one or more PNG images into a single PDF file.

+ ${createFileInputHTML({ multiple: true, accept: 'image/png', showControls: true })} +
+ + `, + 'pdf-to-webp': () => ` +

PDF to WebP

+

Convert each page of a PDF file into a modern WebP image.

+ ${createFileInputHTML()} +
+ + `, + 'webp-to-pdf': () => ` +

WebP to PDF

+

Convert one or more WebP images into a single PDF file.

+ ${createFileInputHTML({ multiple: true, accept: 'image/webp', showControls: true })} +
+ + `, + edit: () => ` +

PDF Studio

+

An all-in-one PDF workspace where you can annotate, draw, highlight, redact, add comments and shapes, take screenshots, and view PDFs.

+ ${createFileInputHTML()} +
+ + `, + 'delete-pages': () => ` +

Delete Pages

+

Remove specific pages or ranges of pages from your PDF file.

+ ${createFileInputHTML()} +
+ + `, + 'add-blank-page': () => ` +

Add Blank Page

+

Insert a new blank page at a specific position in your document.

+ ${createFileInputHTML()} +
+ + `, + 'extract-pages': () => ` +

Extract Pages

+

Extract specific pages from a PDF into separate files. Your files will download in a ZIP archive.

+ ${createFileInputHTML()} +
+ + `, + +'add-watermark': () => ` +

Add Watermark

+

Apply a text or image watermark to every page of your PDF document.

+ ${createFileInputHTML()} +
+ + + +`, + + +'add-header-footer': () => ` +

Add Header & Footer

+

Add custom text to the top and bottom margins of every page.

+ ${createFileInputHTML()} +
+ + +`, + + + 'image-to-pdf': () => ` +

Image to PDF Converter

+

Combine multiple images into a single PDF. Drag and drop to reorder.

+ ${createFileInputHTML({ multiple: true, accept: 'image/jpeg,image/png,image/webp', showControls: true })} +
    + + `, + +'change-permissions': () => ` +

    Change PDF Permissions

    +

    Unlock a PDF and re-save it with new passwords and permissions.

    + ${createFileInputHTML()} +
    + + +`, + + + 'pdf-to-markdown': () => ` +

    PDF to Markdown

    +

    Convert a PDF's text content into a structured Markdown file.

    + ${createFileInputHTML({ accept: '.pdf' })} +
    + + + `, + 'txt-to-pdf': () => ` +

    Text to PDF

    +

    Type or paste your text below and convert it to a PDF with custom formatting.

    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + `, + 'invert-colors': () => ` +

    Invert PDF Colors

    +

    Convert your PDF to a "dark mode" by inverting its colors. This works best on simple text and image documents.

    + ${createFileInputHTML()} +
    + + `, + 'view-metadata': () => ` +

    View PDF Metadata

    +

    Upload a PDF to view its internal properties, such as Title, Author, and Creation Date.

    + ${createFileInputHTML()} +
    + + `, + 'reverse-pages': () => ` +

    Reverse PDF Pages

    +

    Flip the order of all pages in your document, making the last page the first.

    + ${createFileInputHTML()} +
    + + `, + 'md-to-pdf': () => ` +

    Markdown to PDF

    +

    Write in Markdown, select your formatting options, and get a high-quality, multi-page PDF.
    Note: Images linked from the web (e.g., https://...) require an internet connection to be rendered.

    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    + + `, + 'svg-to-pdf': () => ` +

    SVG to PDF

    +

    Convert one or more SVG vector images into a single PDF file.

    + ${createFileInputHTML({ multiple: true, accept: 'image/svg+xml', showControls: true })} +
    + + `, + 'bmp-to-pdf': () => ` +

    BMP to PDF

    +

    Convert one or more BMP images into a single PDF file.

    + ${createFileInputHTML({ multiple: true, accept: 'image/bmp', showControls: true })} +
    + + `, + 'heic-to-pdf': () => ` +

    HEIC to PDF

    +

    Convert one or more HEIC (High Efficiency) images from your iPhone or camera into a single PDF file.

    + ${createFileInputHTML({ multiple: true, accept: '.heic,.heif', showControls: true })} +
    + + `, + 'tiff-to-pdf': () => ` +

    TIFF to PDF

    +

    Convert one or more single or multi-page TIFF images into a single PDF file.

    + ${createFileInputHTML({ multiple: true, accept: 'image/tiff', showControls: true })} +
    + + `, + 'pdf-to-bmp': () => ` +

    PDF to BMP

    +

    Convert each page of a PDF file into a BMP image. Your files will be downloaded in a ZIP archive.

    + ${createFileInputHTML()} +
    + + `, + 'pdf-to-tiff': () => ` +

    PDF to TIFF

    +

    Convert each page of a PDF file into a high-quality TIFF image. Your files will be downloaded in a ZIP archive.

    + ${createFileInputHTML()} +
    + + `, + + 'split-in-half': () => ` +

    Split Pages in Half

    +

    Choose a method to divide every page of your document into two separate pages.

    + ${createFileInputHTML()} +
    + + + `, + 'page-dimensions': () => ` +

    Analyze Page Dimensions

    +

    Upload a PDF to see the precise dimensions, standard size, and orientation of every page.

    + ${createFileInputHTML()} +
    + + + `, + + 'n-up': () => ` +

    N-Up Page Arrangement

    +

    Combine multiple pages from your PDF onto a single sheet. This is great for creating booklets or proof sheets.

    + ${createFileInputHTML()} +
    + + + `, + + 'duplicate-organize': () => ` +

    Page Manager

    +

    Drag pages to reorder them. Use the icon to duplicate a page or the icon to delete it.

    + ${createFileInputHTML()} +
    + + + `, + + 'combine-single-page': () => ` +

    Combine to a Single Page

    +

    Stitch all pages of your PDF together vertically to create one continuous, scrollable page.

    + ${createFileInputHTML()} +
    + + + `, + + 'fix-dimensions': () => ` +

    Standardize Page Dimensions

    +

    Convert all pages in your PDF to a uniform size. Choose a standard format or define a custom dimension.

    + ${createFileInputHTML()} +
    + + + `, + + 'change-background-color': () => ` +

    Change Background Color

    +

    Select a new background color for every page of your PDF.

    + ${createFileInputHTML()} +
    + + `, + + 'change-text-color': () => ` +

    Change Text Color

    +

    Change the color of dark text in your PDF. This process converts pages to images, so text will not be selectable in the final file.

    + ${createFileInputHTML()} +
    + + `, + + 'compare-pdfs': () => ` +

    Compare PDFs

    +

    Upload two files to visually compare them using either an overlay or a side-by-side view.

    + +
    +
    +
    + +

    Upload Original PDF

    +
    + +
    +
    +
    + +

    Upload Revised PDF

    +
    + +
    +
    + + + `, + + 'ocr-pdf': () => ` +

    OCR PDF

    +

    Convert scanned PDFs into searchable documents. Select one or more languages present in your file for the best results.

    + ${createFileInputHTML()} +
    + + + + + + +`, + + 'word-to-pdf': () => ` +

    Word to PDF Converter

    +

    Upload a .docx file to convert it into a high-quality PDF with selectable text. Complex layouts may not be perfectly preserved.

    + +
    +
    +
    + +

    Click to select a file or drag and drop

    +

    A single .docx file

    +
    + +
    +
    + +
    + + `, + + 'sign-pdf': () => ` +

    Sign PDF

    +

    Create your signature, select it, then click on the document to place. You can drag to move placed signatures.

    + ${createFileInputHTML()} + + + +`, + + 'remove-annotations': () => ` +

    Remove Annotations

    +

    Select the types of annotations to remove from all pages or a specific range.

    + ${createFileInputHTML()} +
    + + + +`, + + +cropper: () => ` +

    PDF Cropper

    +

    Upload a PDF to visually crop one or more pages. This tool offers a live preview and two distinct cropping modes.

    + + ${createFileInputHTML()} +
    + + +`, + +'form-filler': () => ` +

    PDF Form Filler

    +

    Upload a PDF to fill in existing form fields. The PDF view on the right will update as you type.

    + ${createFileInputHTML()} +
    + +`, + +}; \ No newline at end of file diff --git a/src/js/utils/helpers.ts b/src/js/utils/helpers.ts new file mode 100644 index 0000000..c488e51 --- /dev/null +++ b/src/js/utils/helpers.ts @@ -0,0 +1,113 @@ +const STANDARD_SIZES = { + 'A4': { width: 595.28, height: 841.89 }, + 'Letter': { width: 612, height: 792 }, + 'Legal': { width: 612, height: 1008 }, + 'Tabloid': { width: 792, height: 1224 }, + 'A3': { width: 841.89, height: 1190.55 }, + 'A5': { width: 419.53, height: 595.28 }, +}; + +export function getStandardPageName(width: any, height: any) { + const tolerance = 1; // Allow for minor floating point variations + for (const [name, size] of Object.entries(STANDARD_SIZES)) { + if ((Math.abs(width - size.width) < tolerance && Math.abs(height - size.height) < tolerance) || + (Math.abs(width - size.height) < tolerance && Math.abs(height - size.width) < tolerance)) { + return name; + } + } + return 'Custom'; +} + +export function convertPoints(points: any, unit: any) { + let result = 0; + switch (unit) { + case 'in': + result = points / 72; + break; + case 'mm': + result = (points / 72) * 25.4; + break; + case 'px': + result = points * (96 / 72); // Assuming 96 DPI + break; + default: // 'pt' + result = points; + break; + } + return result.toFixed(2); +} + +export const hexToRgb = (hex: any) => { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16) / 255, + g: parseInt(result[2], 16) / 255, + b: parseInt(result[3], 16) / 255, + } : { r: 0, g: 0, b: 0 }; // Default to black +}; + +export const formatBytes = (bytes: any, decimals = 1) => { + if (bytes === 0) return '0 Bytes'; + const k = 1024; + const dm = decimals < 0 ? 0 : decimals; + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + const i = Math.floor(Math.log(bytes) / Math.log(k)); + return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; +}; + +export const downloadFile = (blob: any, filename: any) => { + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = filename; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); +}; + +export const readFileAsArrayBuffer = (file: any) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = (error) => reject(error); + reader.readAsArrayBuffer(file); + }); +}; + +export function parsePageRanges(rangeString: any, totalPages: any) { + if (!rangeString || rangeString.trim() === '') { + return Array.from({ length: totalPages }, (_, i) => i); + } + + const indices = new Set(); + const parts = rangeString.split(','); + + for (const part of parts) { + const trimmedPart = part.trim(); + if (!trimmedPart) continue; + + if (trimmedPart.includes('-')) { + const [start, end] = trimmedPart.split('-').map(Number); + if (isNaN(start) || isNaN(end) || start < 1 || end > totalPages || start > end) { + console.warn(`Invalid range skipped: ${trimmedPart}`); + continue; + } + + for (let i = start; i <= end; i++) { + indices.add(i - 1); + } + } else { + const pageNum = Number(trimmedPart); + + if (isNaN(pageNum) || pageNum < 1 || pageNum > totalPages) { + console.warn(`Invalid page number skipped: ${trimmedPart}`); + continue; + } + indices.add(pageNum - 1); + } + } + + // @ts-expect-error TS(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message + return Array.from(indices).sort((a, b) => a - b); +} \ No newline at end of file diff --git a/terms.html b/terms.html new file mode 100644 index 0000000..660c7ad --- /dev/null +++ b/terms.html @@ -0,0 +1,140 @@ + + + + + + Terms and Conditions - Bentopdf + + + + + + + + + +
    +
    +

    Terms and Conditions

    +

    Last Updated: September 14, 2025

    + + +
    +
    + + + + + diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..70ad997 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,61 @@ +// { +// "compilerOptions": { +// "target": "ES2022", +// "useDefineForClassFields": true, +// "module": "ESNext", +// "lib": ["ES2022", "DOM", "DOM.Iterable"], +// "types": ["vite/client"], +// "skipLibCheck": true, + +// /* Bundler mode */ +// "moduleResolution": "bundler", +// "allowImportingTsExtensions": true, +// "verbatimModuleSyntax": true, +// "moduleDetection": "force", +// "noEmit": true, + +// /* Linting */ +// "strict": true, +// "noUnusedLocals": true, +// "noUnusedParameters": true, +// "erasableSyntaxOnly": true, +// "noFallthroughCasesInSwitch": true, +// "noUncheckedSideEffectImports": true +// }, +// "include": ["src"] +// } + +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + + /* Easier module handling for Vite */ + "moduleResolution": "bundler", + "allowJs": true, + "checkJs": false, + "skipLibCheck": true, + "noEmit": true, + "allowImportingTsExtensions": true, + + /* Disable strict checks for now */ + "strict": false, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noFallthroughCasesInSwitch": false, + "noUncheckedSideEffectImports": false, + + /* Fix for ArrayBuffer type issues */ + "noImplicitAny": false, + + /* Quality-of-life options */ + "isolatedModules": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] +} + diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..c2019c6 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from 'vite'; +import tailwindcss from '@tailwindcss/vite' +import { nodePolyfills } from 'vite-plugin-node-polyfills'; + +export default defineConfig({ + plugins: [ + tailwindcss(), + nodePolyfills({ + include: ['buffer', 'stream', 'util', 'zlib', 'process'], + globals: { + Buffer: true, + global: true, + process: true, + }, + }), + ], + resolve: { + alias: { + stream: 'stream-browserify', + zlib: 'browserify-zlib', + }, + }, + optimizeDeps: { + include: ['pdfkit', 'blob-stream'], + }, +}); \ No newline at end of file