diff --git a/.gitignore b/.gitignore
index ff9a3bc59..6eef0278f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,122 +1,5 @@
-
-
-### Eclipse ###
-.metadata
-bin/
-tmp/
-*.tmp
-*.bak
-*.swp
-*~.nib
-local.properties
-.settings/
-.loadpath
-.recommenders
-.classpath
-.project
-version.properties
-pipeline/
-
-#### Stirling-PDF Files ###
-customFiles/
-configs/
-watchedFolders/
-
-
-# Gradle
-.gradle
-.lock
-
-# External tool builders
-.externalToolBuilders/
-
-# Locally stored "Eclipse launch configurations"
-*.launch
-
-# PyDev specific (Python IDE for Eclipse)
-*.pydevproject
-
-# CDT-specific (C/C++ Development Tooling)
-.cproject
-
-# CDT- autotools
-.autotools
-
-# Java annotation processor (APT)
-.factorypath
-
-# PDT-specific (PHP Development Tools)
-.buildpath
-
-# sbteclipse plugin
-.target
-
-# Tern plugin
-.tern-project
-
-# TeXlipse plugin
-.texlipse
-
-# STS (Spring Tool Suite)
-.springBeans
-
-# Code Recommenders
-.recommenders/
-
-# Annotation Processing
-.apt_generated/
-.apt_generated_test/
-
-# Scala IDE specific (Scala & Java development for Eclipse)
-.cache-main
-.scala_dependencies
-.worksheet
-
-# Uncomment this line if you wish to ignore the project description file.
-# Typically, this file would be tracked if it contains build/dependency configurations:
-#.project
-
-### Eclipse Patch ###
-# Spring Boot Tooling
-.sts4-cache/
-
-### Git ###
-# Created by git for backups. To disable backups in Git:
-# $ git config --global mergetool.keepBackup false
-*.orig
-
-# Created by git when using merge tools for conflicts
-*.BACKUP.*
-*.BASE.*
-*.LOCAL.*
-*.REMOTE.*
-*_BACKUP_*.txt
-*_BASE_*.txt
-*_LOCAL_*.txt
-*_REMOTE_*.txt
-
-### Java ###
-# Compiled class file
-*.class
-
-# Log file
-*.log
-
-# BlueJ files
-*.ctxt
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.nar
-*.ear
-*.zip
-*.tar.gz
-*.rar
-*.db
-/build
-
-/.vscode
\ No newline at end of file
+/node_modules/
+.env
+/testFiles/
+/ignore/
+*.code-workspace
\ No newline at end of file
diff --git a/CONTRIBUTE.md b/CONTRIBUTE.md
new file mode 100644
index 000000000..460783c61
--- /dev/null
+++ b/CONTRIBUTE.md
@@ -0,0 +1,30 @@
+# Contribute
+
+This file should introduce you with the concepts and tools used in this project.
+
+## PDF Library Docs
+- [pdf-lib](https://pdf-lib.js.org) - js
+- [pdfcpu](https://pdfcpu.io) - go-wasm
+
+## Adding a PDF Function
+
+In order to add a PDF-Function there are several files that need to be changed. If the function is on the backend only, or on only on the frontend, you just need to add it to one of the locations. If it is available on both, you need to update both locations.
+Dependency Injection is used to accomodate for different imports across platforms.
+
+Backend functions can have different implementations than their frontend counterparts if neccesary. Otherwise they can just link to their frontend implementation.
+
+Registering functions will also pass them their dependencies for the specific target platform (Node, Browser)
+
+### Backend
+
+[Register Functions](/functions.js)\
+[Functions Folder](/functions/)
+
+Examples that go in the node-functions folder: server-side-only functions, different implementation for backend
+
+### Frontend
+
+[Register Functions](/public/functions.js)\
+[Functions Folder](/public/functions/)
+
+Examples that go in the browser-functions folder: client-side-only functions, shared functions
diff --git a/README.md b/README.md
index 771702452..a9a7f6292 100644
--- a/README.md
+++ b/README.md
@@ -1,268 +1,137 @@
-
Stirling-PDF
-
+# StirlingPDF rewrite
-[](https://hub.docker.com/r/frooodle/s-pdf)
-[](https://discord.gg/Cn8pWhQRxZ)
-[](https://github.com/Frooodle/Stirling-PDF/)
-[](https://github.com/Frooodle/stirling-pdf)
-[](https://www.paypal.com/paypalme/froodleplex)
-[](https://github.com/sponsors/Frooodle)
+This is the development repository for the new StirlingPDF backend. With the power of JS, WASM & GO this will provide almost all functionality SPDF can do currently directly on the client. For automation purposes this will still provide an API to automate your workflows.
-[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/Frooodle/Stirling-PDF/tree/digitalOcean&refcode=c3210994b1af)
+## Try the new API!
-This is a powerful locally hosted web based PDF manipulation tool using docker that allows you to perform various operations on PDF files, such as splitting merging, converting, reorganizing, adding images, rotating, compressing, and more. This locally hosted web application started as a 100% ChatGPT-made application and has evolved to include a wide range of features to handle all your PDF needs.
+[](https://documenter.getpostman.com/view/30633786/2s9YRB1Wto)
-Stirling PDF makes no outbound calls for any record keeping or tracking.
+## Understanding Workflows
-All files and PDFs are either purely client side, in server memory only during the execution of the task or within a temporay file only for execution of the task.
-Any file which has been downloaded by the user will have already been deleted from the server by that time.
+Workflows define how to apply operations to a PDF, including their order and relations with eachother.
-Feel free to request any features or bug fixes either in github issues or our [Discord](https://discord.gg/Cn8pWhQRxZ)
+Workflows can be created via the web-ui and then exported or, if you want to brag a bit, you can create the JSON object yourself.
-
+### Basics
+
+To create your own, you have to understand a few key features first. You can also look at more examples our github repository.
+
+``` json
+{
+ "outputOptions": {
+ "zip": false
+ },
+ "operations": [
+ {
+ "type": "extract",
+ "values": {
+ "pagesToExtractArray": [0, 2]
+ },
+ "operations": []
+ }
+ ]
+}
+```
+
+The workflow above will extract the first (p\[0\]) and third (p\[2\]) page of the document.
+
+You can also nest workflows like this:
+
+``` json
+{
+ "outputOptions": {
+ "zip": false
+ },
+ "operations": [
+ {
+ "type": "extract",
+ "values": {
+ "pagesToExtractArray": [0, 2]
+ },
+ "operations": [
+ {
+ "type": "impose",
+ "values": {
+ "nup": 2, // 2 pages of the input document will be put on one page of the output document.
+ "format": "A4L" // A4L -> The page size of the Ouput will be an A4 in Landscape. You can also use other paper formats and "P" for portrait output.
+ },
+ "operations": []
+ }
+ ]
+ }
+ ]
+}
+```
+
+If you look at it closely, you will see that the extract operation has another nested operation of the type impose. This workflow will produce a PDF with the 1st and 2nd page of the input on one single page.
+
+### Advanced
+
+If that is not enought for you usecase, there is also the possibility to connect operations with eachother.
+
+You can also do different operations to produce two different output PDFs from one input.
+
+If you are interested in learning about this, take a look at the Example workflows provided in the repository, ask on the discord, or wait for me to finish this documentation.
## Features
-- Dark mode support.
-- Custom download options (see [here](https://github.com/Frooodle/Stirling-PDF/blob/main/images/settings.png) for example)
-- Parallel file processing and downloads
-- API for integration with external scripts
-- Optional Login and Authentication support (see [here](https://github.com/Frooodle/Stirling-PDF/tree/main#login-authentication) for documentation)
+### New
-## **PDF Features**
+- [x] Client side PDF-Manipulation
+- [x] Workflows
+- [ ] Stateful UI
+- [ ] Node based editing of them
+- [ ] Propper auth using passportjs
-### **Page Operations**
-- Full interactive GUI for merging/splitting/rotating/moving PDFs and their pages.
-- Merge multiple PDFs together into a single resultant file.
-- Split PDFs into multiple files at specified page numbers or extract all pages as individual files.
-- Reorganize PDF pages into different orders.
-- Rotate PDFs in 90-degree increments.
-- Remove pages.
-- Multi-page layout (Format PDFs into a multi-paged page).
-- Scale page contents size by set %.
-- Adjust Contrast.
-- Crop PDF.
-- Auto Split PDF (With physically scanned page dividers).
-- Extract page(s).
-- Convert PDF to a single page.
+### Functions
-### **Conversion Operations**
-- Convert PDFs to and from images.
-- Convert any common file to PDF (using LibreOffice).
-- Convert PDF to Word/Powerpoint/Others (using LibreOffice).
-- Convert HTML to PDF.
-- URL to PDF.
-- Markdown to PDF.
+Current functions of spdf and their progress in this repo.
-### **Security & Permissions**
-- Add and remove passwords.
-- Change/set PDF Permissions.
-- Add watermark(s).
-- Certify/sign PDFs.
-- Sanitize PDFs.
-- Auto-redact text.
+- [x] Merge
+- [x] Split
+- [x] Rotate
+- [x] Multi-Page-Layout
+- [x] Adjust page size/scale
+- [ ] Organize
+- [ ] Change Metadata
+- [ ] Add Watermark
-### **Other Operations**
-- Add/Generate/Write signatures.
-- Repair PDFs.
-- Detect and remove blank pages.
-- Compare 2 PDFs and show differences in text.
-- Add images to PDFs.
-- Compress PDFs to decrease their filesize (Using OCRMyPDF).
-- Extract images from PDF.
-- Extract images from Scans.
-- Add page numbers.
-- Auto rename file by detecting PDF header text.
-- OCR on PDF (Using OCRMyPDF).
-- PDF/A conversion (Using OCRMyPDF).
-- Edit metadata.
-- Flatten PDFs.
-- Get all information on a PDF to view or export as JSON.
+
+- [ ] Remove Pages
+- [ ] Remove Blank Pages
+- [ ] Detect/Split Scanned photos
-For a overview of the tasks and the technology each uses please view [groups.md](https://github.com/Frooodle/Stirling-PDF/blob/main/Groups.md)
-Hosted instance/demo of the app can be seen [here](https://pdf.adminforge.de/) hosted by the team at adminforge.de
+
-## Technologies used
-- Spring Boot + Thymeleaf
-- PDFBox
-- [LibreOffice](https://www.libreoffice.org/discover/libreoffice/) for advanced conversions
-- [OcrMyPdf](https://github.com/ocrmypdf/OCRmyPDF)
-- HTML, CSS, JavaScript
-- Docker
-- PDF.js
-- PDF-LIB.js
+- [ ] Repair
+- [ ] Compress
+- [ ] Flatten
+- [ ] Compare/Diff
-## How to use
+
-### Locally
-Please view https://github.com/Frooodle/Stirling-PDF/blob/main/LocalRunGuide.md
+- [ ] Sign
+- [ ] Sign with Certificate
+- [ ] Add Password
+- [ ] Remove Password
+- [ ] Change Permissions
-### Docker
-https://hub.docker.com/r/frooodle/s-pdf
+
-Stirling PDF has 3 different versions, a Full version, Lite, and ultra-Lite. Depending on the types of features you use you may want a smaller image to save on space.
-To see what the different versions offer please look at our [version mapping](https://github.com/Frooodle/Stirling-PDF/blob/main/Version-groups.md)
-For people that don't mind about space optimization just use the latest tag.
-
-
-
+- [ ] Image to PDF
+- [ ] Add image
+- [ ] Extract Images
+- [ ] PDF to Image
+- [ ] OCR
-Docker Run
-```
-docker run -d \
- -p 8080:8080 \
- -v /location/of/trainingData:/usr/share/tesseract-ocr/4.00/tessdata \
- -v /location/of/extraConfigs:/configs \
- -e DOCKER_ENABLE_SECURITY=false \
- --name stirling-pdf \
- frooodle/s-pdf:latest
-
-
- Can also add these for customisation but are not required
-
- -v /location/of/customFiles:/customFiles \
-```
-Docker Compose
-```
-version: '3.3'
-services:
- stirling-pdf:
- image: frooodle/s-pdf:latest
- ports:
- - '8080:8080'
- volumes:
- - /location/of/trainingData:/usr/share/tesseract-ocr/4.00/tessdata #Required for extra OCR languages
- - /location/of/extraConfigs:/configs
-# - /location/of/customFiles:/customFiles/
- environment:
- - DOCKER_ENABLE_SECURITY=false
-```
+
+- [ ] Convert file to PDF
+- [ ] PDF to Text/RTF
+- [ ] PDF to HTML
+- [ ] PDF to XML
-## Enable OCR/Compression feature
-Please view https://github.com/Frooodle/Stirling-PDF/blob/main/HowToUseOCR.md
+## Contribute
-## Want to add your own language?
-Stirling PDF currently supports 18!
-- English (English) (en_GB)
-- English (US) (en_US)
-- Arabic (العربية) (ar_AR)
-- German (Deutsch) (de_DE)
-- French (Français) (fr_FR)
-- Spanish (Español) (es_ES)
-- Chinese (简体中文) (zh_CN)
-- Catalan (Català) (ca_CA)
-- Italian (Italiano) (it_IT)
-- Swedish (Svenska) (sv_SE)
-- Polish (Polski) (pl_PL)
-- Romanian (Română) (ro_RO)
-- Korean (한국어) (ko_KR)
-- Portuguese Brazilian (Português) (pt_BR)
-- Russian (Русский) (ru_RU)
-- Basque (Euskara) (eu_ES)
-- Japanese (日本語) (ja_JP)
-- Dutch (Nederlands) (nl_NL)
-
-If you want to add your own language to Stirling-PDF please refer
-https://github.com/Frooodle/Stirling-PDF/blob/main/HowToAddNewLanguage.md
-
-And please create a PR to merge it back in so others can use it!
-
-## How to View
-1. Open a web browser and navigate to `http://localhost:8080/`
-2. Use the application by following the instructions on the website.
-
-
-## Customisation
-Stirling PDF allows easy customization of the app.
-Includes things like
-- Custom application name
-- Custom slogans, icons, images, and even custom HTML (via file overrides)
-
-
-There are two options for this, either using the generated settings file ``settings.yml``
-This file is located in the ``/configs`` directory and follows standard YAML formatting
-
-Environment variables are also supported and would override the settings file
-For example in the settings.yml you have
-```
-system:
- defaultLocale: 'en-US'
-```
-
-To have this via an environment variable you would have ``SYSTEM_DEFAULTLOCALE``
-
-The Current list of settings is
-```
-security:
- enableLogin: false # set to 'true' to enable login
- csrfDisabled: true
-
-system:
- defaultLocale: 'en-US' # Set the default language (e.g. 'de-DE', 'fr-FR', etc)
- googlevisibility: false # 'true' to allow Google visibility (via robots.txt), 'false' to disallow
- customStaticFilePath: '/customFiles/static/' # Directory path for custom static files
-
-#ui:
-# appName: exampleAppName # Application's visible name
-# homeDescription: I am a description # Short description or tagline shown on homepage.
-# appNameNavbar: navbarName # Name displayed on the navigation bar
-
-endpoints:
- toRemove: [] # List endpoints to disable (e.g. ['img-to-pdf', 'remove-pages'])
- groupsToRemove: [] # List groups to disable (e.g. ['LibreOffice'])
-
-metrics:
- enabled: true # 'true' to enable Info APIs endpoints (view http://localhost:8080/swagger-ui/index.html#/API to learn more), 'false' to disable
-```
-### Extra notes
-- Endpoints. Currently, the endpoints ENDPOINTS_TO_REMOVE and GROUPS_TO_REMOVE can include comma separate lists of endpoints and groups to disable as example ENDPOINTS_TO_REMOVE=img-to-pdf,remove-pages would disable both image-to-pdf and remove pages, GROUPS_TO_REMOVE=LibreOffice Would disable all things that use LibreOffice. You can see a list of all endpoints and groups [here](https://github.com/Frooodle/Stirling-PDF/blob/main/groups.md)
-- customStaticFilePath. Customise static files such as the app logo by placing files in the /customFiles/static/ directory. An example of customising app logo is placing a /customFiles/static/favicon.svg to override current SVG. This can be used to change any images/icons/css/fonts/js etc in Stirling-PDF
-
-### Environment only parameters
-- ``SYSTEM_ROOTURIPATH`` ie set to ``/pdf-app`` to Set the application's root URI to ``localhost:8080/pdf-app``
-- ``SYSTEM_CONNECTIONTIMEOUTMINUTES`` to set custom connection timeout values
-- ``DOCKER_ENABLE_SECURITY`` to tell docker to download security jar (required as true for auth login)
-
-## API
-For those wanting to use Stirling-PDFs backend API to link with their own custom scripting to edit PDFs you can view all existing API documentation
-[here](https://app.swaggerhub.com/apis-docs/Frooodle/Stirling-PDF/) or navigate to /swagger-ui/index.html of your stirling-pdf instance for your versions documentation (Or by following the API button in your settings of Stirling-PDF)
-
-
-## Login authentication
-
-### Prerequisites:
-- User must have the folder ./configs volumed within docker so that it is retained during updates.
-- Docker uses must download the security jar version by setting ``DOCKER_ENABLE_SECURITY`` to ``true`` in environment variables.
-- Then either enable login via the settings.yml file or via setting ``SECURITY_ENABLE_LOGIN`` to ``true``
-- Now the initial user will be generated with username ``admin`` and password ``stirling``. On login you will be forced to change the password to a new one. You can also use the environment variables ``SECURITY_INITIALLOGIN_USERNAME`` and ``SECURITY_INITIALLOGIN_PASSWORD`` to set your own straight away (Recommended to remove them after user creation).
-
-Once the above has been done, on restart, a new stirling-pdf-DB.mv.db will show if everything worked.
-
-When you login to Stirling PDF you will be redirected to /login page to login with those default credentials. After login everything should function as normal
-
-To access your account settings go to Account settings in the settings cog menu (top right in navbar) This Account settings menu is also where you find your API key.
-
-To add new users go to the bottom of Account settings and hit 'Admin Settings', here you can add new users. The different roles mentioned within this are for rate limiting. This is a Work in progress which will be expanding on more in future
-
-For API usage you must provide a header with 'X-API-Key' and the associated API key for that user.
-
-
-## FAQ
-
-### Q1: What are your planned features?
-- Progress bar/Tracking
-- Full custom logic pipelines to combine multiple operations together.
-- Folder support with auto scanning to perform operations on
-- Redact text (Via UI not just automated way)
-- Add Forms
-- Annotations
-- Multi page layout (Stich PDF pages together) support x rows y columns and custom page sizing
-- Fill forms mannual and automatic
-
-### Q2: Why is my application downloading .htm files?
-This is a issue caused commonly by your NGINX congifuration. The default file upload size for NGINX is 1MB, you need to add the following in your Nginx sites-available file. ``client_max_body_size SIZE;`` Where "SIZE" is 50M for example for 50MB files.
-
-### Q3: Why is my download timing out
-NGINX has timeout values by default so if you are running Stirling-PDF behind NGINX you may need to set a timeout value such as adding the config ``proxy_read_timeout 3600;``
+For initial instructions look at [CONTRIBUTE.md](./CONTRIBUTE.md)
\ No newline at end of file
diff --git a/functions.js b/functions.js
new file mode 100644
index 000000000..c6260f4ab
--- /dev/null
+++ b/functions.js
@@ -0,0 +1,38 @@
+import PDFLib from 'pdf-lib';
+import * as pdfcpuWraopper from "./public/wasm/pdfcpu-wrapper-node.js";
+
+import { extractPages as dependantExtractPages } from "./public/functions/extractPages.js";
+import { impose as dependantImpose } from './public/functions/impose.js';
+import { mergePDFs as dependantMergePDFs } from './public/functions/mergePDFs.js';
+import { rotatePages as dependantRotatePages } from './public/functions/rotatePages.js';
+import { scaleContent as dependantScaleContent} from './public/functions/scaleContent.js';
+import { scalePage as dependantScalePage } from './public/functions/scalePage.js';
+import { splitPDF as dependantSplitPDF } from './public/functions/splitPDF.js';
+
+export async function extractPages(snapshot, pagesToExtractArray) {
+ return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib);
+}
+
+export async function impose(snapshot, nup, format) {
+ return dependantImpose(snapshot, nup, format, pdfcpuWraopper);
+}
+
+export async function mergePDFs(snapshots) {
+ return dependantMergePDFs(snapshots, PDFLib);
+}
+
+export async function rotatePages(snapshot, rotation) {
+ return dependantRotatePages(snapshot, rotation, PDFLib);
+}
+
+export async function scaleContent(snapshot, scaleFactor) {
+ return dependantScaleContent(snapshot, scaleFactor, PDFLib);
+}
+
+export async function scalePage(snapshot, pageSize) {
+ return dependantScalePage(snapshot, pageSize, PDFLib);
+}
+
+export async function splitPDF(snapshot, splitAfterPageArray) {
+ return dependantSplitPDF(snapshot, splitAfterPageArray, PDFLib);
+}
\ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 000000000..cf6c87add
--- /dev/null
+++ b/index.js
@@ -0,0 +1,20 @@
+
+import api from './routes/api/index.js';
+
+import express from 'express';
+const app = express();
+const PORT = 8080;
+
+// Static Middleware
+app.use(express.static('./public'));
+
+app.get('/', function (req, res, next) { // TODO: Use EJS?
+ res.render('home.ejs');
+});
+
+app.use("/api/", api);
+
+app.listen(PORT, function (err) {
+ if (err) console.log(err);
+ console.log(`http://localhost:${PORT}`);
+});
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 000000000..cee0c2a9b
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,842 @@
+{
+ "name": "pdfjs",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@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==",
+ "requires": {
+ "pako": "^1.0.6"
+ }
+ },
+ "@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==",
+ "requires": {
+ "pako": "^1.0.10"
+ }
+ },
+ "@wasmer/wasmfs": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@wasmer/wasmfs/-/wasmfs-0.12.0.tgz",
+ "integrity": "sha512-m1ftchyQ1DfSenm5XbbdGIpb6KJHH5z0gODo3IZr6lATkj4WXfX/UeBTZ0aG9YVShBp+kHLdUHvOkqjy6p/GWw==",
+ "requires": {
+ "memfs": "3.0.4",
+ "pako": "^1.0.11",
+ "tar-stream": "^2.1.0"
+ }
+ },
+ "accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "requires": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ }
+ },
+ "archiver": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-6.0.1.tgz",
+ "integrity": "sha512-CXGy4poOLBKptiZH//VlWdFuUC1RESbdZjGjILwBuZ73P7WkAUN0htfSfBq/7k6FRFlpu7bg4JOkj1vU9G6jcQ==",
+ "requires": {
+ "archiver-utils": "^4.0.1",
+ "async": "^3.2.4",
+ "buffer-crc32": "^0.2.1",
+ "readable-stream": "^3.6.0",
+ "readdir-glob": "^1.1.2",
+ "tar-stream": "^3.0.0",
+ "zip-stream": "^5.0.1"
+ },
+ "dependencies": {
+ "tar-stream": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz",
+ "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==",
+ "requires": {
+ "b4a": "^1.6.4",
+ "fast-fifo": "^1.2.0",
+ "streamx": "^2.15.0"
+ }
+ }
+ }
+ },
+ "archiver-utils": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-4.0.1.tgz",
+ "integrity": "sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==",
+ "requires": {
+ "glob": "^8.0.0",
+ "graceful-fs": "^4.2.0",
+ "lazystream": "^1.0.0",
+ "lodash": "^4.17.15",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
+ "async": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
+ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
+ },
+ "b4a": {
+ "version": "1.6.4",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz",
+ "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw=="
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+ },
+ "bl": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+ "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+ "requires": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "requires": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ }
+ },
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "requires": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="
+ },
+ "busboy": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
+ "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+ "requires": {
+ "streamsearch": "^1.1.0"
+ }
+ },
+ "bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
+ },
+ "call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ }
+ },
+ "compress-commons": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-5.0.1.tgz",
+ "integrity": "sha512-MPh//1cERdLtqwO3pOFLeXtpuai0Y2WCd5AhtKxznqM7WtaMYaOEMSgn45d9D10sIHSfIKE603HlOp8OPGrvag==",
+ "requires": {
+ "crc-32": "^1.2.0",
+ "crc32-stream": "^5.0.0",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ }
+ },
+ "content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "requires": {
+ "safe-buffer": "5.2.1"
+ }
+ },
+ "content-type": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="
+ },
+ "cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "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=="
+ },
+ "crc-32": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="
+ },
+ "crc32-stream": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-5.0.0.tgz",
+ "integrity": "sha512-B0EPa1UK+qnpBZpG+7FgPCu0J2ETLpXq09o9BkLkEAhdB6Z61Qo4pJ3JYu0c+Qi+/SAL7QThqnzS06pmSSyZaw==",
+ "requires": {
+ "crc-32": "^1.2.0",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+ },
+ "destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
+ },
+ "etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
+ },
+ "express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "requires": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ }
+ },
+ "express-fileupload": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.4.1.tgz",
+ "integrity": "sha512-9F6SkbxbEOA9cYOBZ8tnn238jL+bGfacQuUO/JqPWp5t+piUcoDcESvKwAXsQV7IHGxmI5bMj3QxMWOKOIsMCg==",
+ "requires": {
+ "busboy": "^1.6.0"
+ }
+ },
+ "fast-extend": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/fast-extend/-/fast-extend-1.0.2.tgz",
+ "integrity": "sha512-XXA9RmlPatkFKUzqVZAFth18R4Wo+Xug/S+C7YlYA3xrXwfPlW3dqNwOb4hvQo7wZJ2cNDYhrYuPzVOfHy5/uQ=="
+ },
+ "fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="
+ },
+ "finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "requires": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ }
+ },
+ "forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+ },
+ "fresh": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+ "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
+ },
+ "fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
+ },
+ "fs-monkey": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-0.3.3.tgz",
+ "integrity": "sha512-FNUvuTAJ3CqCQb5ELn+qCbGR/Zllhf2HtwsdAtBi59s1WeCjKMT81fHcSu7dwIskqGVK+MmOrb7VOBlq3/SItw=="
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+ },
+ "function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="
+ },
+ "get-intrinsic": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
+ "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
+ "requires": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3"
+ }
+ },
+ "glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ }
+ },
+ "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=="
+ },
+ "has": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
+ "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ=="
+ },
+ "has-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
+ "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg=="
+ },
+ "has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
+ },
+ "http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "requires": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "ipaddr.js": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+ "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
+ },
+ "lazystream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+ "requires": {
+ "readable-stream": "^2.0.5"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "requires": {
+ "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"
+ }
+ },
+ "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=="
+ },
+ "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==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
+ },
+ "memfs": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.0.4.tgz",
+ "integrity": "sha512-OcZEzwX9E5AoY8SXjuAvw0DbIAYwUzV/I236I8Pqvrlv7sL/Y0E9aRCon05DhaV8pg1b32uxj76RgW0s5xjHBA==",
+ "requires": {
+ "fast-extend": "1.0.2",
+ "fs-monkey": "0.3.3"
+ }
+ },
+ "merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
+ "methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
+ },
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
+ },
+ "mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "requires": {
+ "mime-db": "1.52.0"
+ }
+ },
+ "minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+ },
+ "object-inspect": {
+ "version": "1.13.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz",
+ "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g=="
+ },
+ "on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "requires": {
+ "ee-first": "1.1.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
+ },
+ "parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ },
+ "path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
+ "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==",
+ "requires": {
+ "@pdf-lib/standard-fonts": "^1.0.0",
+ "@pdf-lib/upng": "^1.0.1",
+ "pako": "^1.0.11",
+ "tslib": "^1.11.1"
+ }
+ },
+ "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=="
+ },
+ "proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "requires": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ }
+ },
+ "qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "requires": {
+ "side-channel": "^1.0.4"
+ }
+ },
+ "queue-tick": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
+ "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag=="
+ },
+ "range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ },
+ "raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "requires": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ }
+ },
+ "readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "readdir-glob": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
+ "requires": {
+ "minimatch": "^5.1.0"
+ }
+ },
+ "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=="
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "requires": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ }
+ }
+ },
+ "serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "requires": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ }
+ },
+ "setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
+ "side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "requires": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ }
+ },
+ "statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
+ },
+ "streamsearch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
+ "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
+ },
+ "streamx": {
+ "version": "2.15.1",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.1.tgz",
+ "integrity": "sha512-fQMzy2O/Q47rgwErk/eGeLu/roaFWV0jVsogDmrszM9uIw8L5OA+t+V93MgYlufNptfjmYR1tOMWhei/Eh7TQA==",
+ "requires": {
+ "fast-fifo": "^1.1.0",
+ "queue-tick": "^1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "requires": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ }
+ },
+ "toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ },
+ "type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "requires": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ },
+ "zip-stream": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-5.0.1.tgz",
+ "integrity": "sha512-UfZ0oa0C8LI58wJ+moL46BDIMgCQbnsb+2PoiJYtonhBsMh2bq1eRBVkvjfVsqbEHd9/EgKPUuL9saSSsec8OA==",
+ "requires": {
+ "archiver-utils": "^4.0.1",
+ "compress-commons": "^5.0.1",
+ "readable-stream": "^3.6.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 000000000..0c554ac6a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,19 @@
+{
+ "name": "pdfjs",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "scripts": {
+ "test": "node ."
+ },
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "@wasmer/wasmfs": "^0.12.0",
+ "archiver": "^6.0.1",
+ "express": "^4.18.2",
+ "express-fileupload": "^1.4.1",
+ "pdf-lib": "^1.17.1"
+ },
+ "type": "module"
+}
diff --git a/public/exampleWorkflows.js b/public/exampleWorkflows.js
new file mode 100644
index 000000000..f13b9ad83
--- /dev/null
+++ b/public/exampleWorkflows.js
@@ -0,0 +1,139 @@
+// JSON Representation of this Node Tree:
+// https://discord.com/channels/1068636748814483718/1099390571493195898/1118192754103693483
+// https://cdn.discordapp.com/attachments/1099390571493195898/1118192753759764520/image.png?ex=6537dba7&is=652566a7&hm=dc46820ef7c34bc37424794966c5f66f93ba0e15a740742c364d47d31ea119a9&
+export const discordWorkflow = {
+ outputOptions: {
+ zip: false
+ },
+ operations: [
+ {
+ type: "extract",
+ values: { "index": "1" },
+ operations: [
+ {
+ type: "removeObjects",
+ values: { "objectNames": "photo, josh" },
+ operations: [
+ {
+ type: "wait",
+ values: { "id": 1 }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ type: "extract",
+ values: { "index": "2-5" },
+ operations: [
+ {
+ type: "fillField",
+ values: { "objectName": "name", "inputValue": "Josh" },
+ operations: [
+ {
+ type: "wait",
+ values: { "id": 1 }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ type: "done", // This gets called when the other merge-ops with the same id finish.
+ values: { "id": 1 },
+ operations: [
+ {
+ type: "merge",
+ values: {},
+ operations: []
+ }
+ ]
+ },
+ {
+ type: "extractImages",
+ values: {},
+ operations: []
+ },
+ {
+ type: "merge",
+ values: {},
+ operations: [
+ {
+ type: "transform",
+ values: { "scale": "2x", "rotation": "90deg" },
+ operations: []
+ }
+ ]
+ }
+ ]
+}
+
+// This will merge all input files into one giant document
+export const mergeOnly = {
+ outputOptions: {
+ zip: false
+ },
+ operations: [
+ {
+ type: "merge",
+ values: {},
+ operations: []
+ }
+ ]
+}
+
+// Extract Pages and store them in a new document
+export const extractOnly = {
+ outputOptions: {
+ zip: false
+ },
+ operations: [
+ {
+ type: "extract",
+ values: { "pagesToExtractArray": [0, 2] },
+ operations: []
+ }
+ ]
+}
+
+// Split a document up into multiple documents
+export const splitOnly = {
+ outputOptions: {
+ zip: false
+ },
+ operations: [
+ {
+ type: "split",
+ values: { "pagesToSplitAfterArray": [2, 10] },
+ operations: []
+ }
+ ]
+}
+
+// Split a document up into multiple documents
+export const rotateOnly = {
+ outputOptions: {
+ zip: false
+ },
+ operations: [
+ {
+ type: "rotate",
+ values: { "rotation": -90 },
+ operations: []
+ }
+ ]
+}
+
+// Split a document up into multiple documents
+export const imposeOnly = {
+ outputOptions: {
+ zip: false
+ },
+ operations: [
+ {
+ type: "impose",
+ values: { "nup": 2, "format": "A4L" },
+ operations: []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/public/functions.js b/public/functions.js
new file mode 100644
index 000000000..ad7ae00ee
--- /dev/null
+++ b/public/functions.js
@@ -0,0 +1,38 @@
+// PDFLib gets importet via index.html script-tag
+import * as pdfcpuWraopper from "./wasm/pdfcpu-wrapper-browser.js";
+
+import { extractPages as dependantExtractPages } from "./functions/extractPages.js";
+import { impose as dependantImpose } from './functions/impose.js';
+import { mergePDFs as dependantMergePDFs } from './functions/mergePDFs.js';
+import { rotatePages as dependantRotatePages } from './functions/rotatePages.js';
+import { scaleContent as dependantScaleContent} from './functions/scaleContent.js';
+import { scalePage as dependantScalePage } from './functions/scalePage.js';
+import { splitPDF as dependantSplitPDF } from './functions/splitPDF.js';
+
+export async function extractPages(snapshot, pagesToExtractArray) {
+ return dependantExtractPages(snapshot, pagesToExtractArray, PDFLib);
+}
+
+export async function impose(snapshot, nup, format) {
+ return dependantImpose(snapshot, nup, format, pdfcpuWraopper);
+}
+
+export async function mergePDFs(snapshots) {
+ return dependantMergePDFs(snapshots, PDFLib);
+}
+
+export async function rotatePages(snapshot, rotation) {
+ return dependantRotatePages(snapshot, rotation, PDFLib);
+}
+
+export async function scaleContent(snapshot, scaleFactor) {
+ return dependantScaleContent(snapshot, scaleFactor, PDFLib);
+}
+
+export async function scalePage(snapshot, pageSize) {
+ return dependantScalePage(snapshot, pageSize, PDFLib);
+}
+
+export async function splitPDF(snapshot, splitAfterPageArray) {
+ return dependantSplitPDF(snapshot, splitAfterPageArray, PDFLib);
+}
\ No newline at end of file
diff --git a/public/functions/extractPages.js b/public/functions/extractPages.js
new file mode 100644
index 000000000..20dee1503
--- /dev/null
+++ b/public/functions/extractPages.js
@@ -0,0 +1,23 @@
+export async function extractPages(snapshot, pagesToExtractArray, PDFLib) {
+ const pdfDoc = await PDFLib.PDFDocument.load(snapshot)
+
+ // TODO: invent a better format for pagesToExtractArray and convert it.
+ return createSubDocument(pdfDoc, pagesToExtractArray, PDFLib);
+};
+
+export async function createSubDocument(pdfDoc, pagesToExtractArray, PDFLib) {
+ const subDocument = await PDFLib.PDFDocument.create();
+
+ // Check that array max number is not larger pdf pages number
+ if(Math.max(...pagesToExtractArray) >= pdfDoc.getPageCount()) {
+ throw new Error(`The PDF document only has ${pdfDoc.getPageCount()} pages and you tried to extract page ${Math.max(...pagesToExtractArray)}`);
+ }
+
+ const copiedPages = await subDocument.copyPages(pdfDoc, pagesToExtractArray);
+
+ for (let i = 0; i < copiedPages.length; i++) {
+ subDocument.addPage(copiedPages[i]);
+ }
+
+ return subDocument.save();
+}
\ No newline at end of file
diff --git a/public/functions/impose.js b/public/functions/impose.js
new file mode 100644
index 000000000..894e44bd4
--- /dev/null
+++ b/public/functions/impose.js
@@ -0,0 +1,12 @@
+export async function impose(snapshot, nup, format, pdfcpuWraopper) {
+ return await pdfcpuWraopper.oneToOne([
+ "pdfcpu.wasm",
+ "nup",
+ "-c",
+ "disable",
+ 'f:' + format,
+ "/output.pdf",
+ String(nup),
+ "input.pdf",
+ ], snapshot);
+}
\ No newline at end of file
diff --git a/public/functions/mergePDFs.js b/public/functions/mergePDFs.js
new file mode 100644
index 000000000..109efc66c
--- /dev/null
+++ b/public/functions/mergePDFs.js
@@ -0,0 +1,13 @@
+export const mergePDFs = async (snapshots, PDFLib) => {
+
+ const mergedPdf = await PDFLib.PDFDocument.create();
+
+ for (let i = 0; i < snapshots.length; i++) {
+ const pdfToMerge = await PDFLib.PDFDocument.load(snapshots[i]);
+
+ const copiedPages = await mergedPdf.copyPages(pdfToMerge, pdfToMerge.getPageIndices());
+ copiedPages.forEach((page) => mergedPdf.addPage(page));
+ }
+
+ return mergedPdf.save();
+};
\ No newline at end of file
diff --git a/public/functions/rotatePages.js b/public/functions/rotatePages.js
new file mode 100644
index 000000000..c42b28862
--- /dev/null
+++ b/public/functions/rotatePages.js
@@ -0,0 +1,16 @@
+export async function rotatePages (snapshot, rotation, PDFLib) {
+ // Load the original PDF file
+ const pdfDoc = await PDFLib.PDFDocument.load(snapshot, {
+ parseSpeed: PDFLib.ParseSpeeds.Fastest,
+ });
+
+ const pages = pdfDoc.getPages();
+
+ pages.forEach(page => {
+ // Change page size
+ page.setRotation(PDFLib.degrees(rotation))
+ });
+
+ // Serialize the modified document
+ return pdfDoc.save();
+};
\ No newline at end of file
diff --git a/public/functions/scaleContent.js b/public/functions/scaleContent.js
new file mode 100644
index 000000000..52847af90
--- /dev/null
+++ b/public/functions/scaleContent.js
@@ -0,0 +1,27 @@
+export async function scaleContent(snapshot, scaleFactor, PDFLib) {
+ // Load the original PDF file
+ const pdfDoc = await PDFLib.PDFDocument.load(snapshot, {
+ parseSpeed: PDFLib.ParseSpeeds.Fastest,
+ });
+
+ const pages = pdfDoc.getPages();
+
+ pages.forEach(page => {
+ const width = page.getWidth();
+ const height = page.getHeight();
+
+ // Scale content
+ page.scaleContent(scaleFactor, scaleFactor);
+ const scaled_diff = {
+ width: Math.round(width - scaleFactor * width),
+ height: Math.round(height - scaleFactor * height),
+ };
+
+ // Center content in new page format
+ page.translateContent(Math.round(scaled_diff.width / 2), Math.round(scaled_diff.height / 2));
+
+ });
+
+ // Serialize the modified document
+ return pdfDoc.save();
+};
\ No newline at end of file
diff --git a/public/functions/scalePage.js b/public/functions/scalePage.js
new file mode 100644
index 000000000..3696280f7
--- /dev/null
+++ b/public/functions/scalePage.js
@@ -0,0 +1,29 @@
+export async function scalePage(snapshot, pageSize, PDFLib) {
+ // Load the original PDF file
+ const pdfDoc = await PDFLib.PDFDocument.load(snapshot, {
+ parseSpeed: PDFLib.ParseSpeeds.Fastest,
+ });
+
+ const new_size = pageSize;
+
+ const pages = pdfDoc.getPages();
+
+ pages.forEach(page => {
+ // Change page size
+ page.setSize(new_size.width, new_size.height);
+ });
+
+ // Serialize the modified document
+ return pdfDoc.save();
+};
+
+export const PageSize = {
+ a4: {
+ width: 594.96,
+ height: 841.92
+ },
+ letter: {
+ width: 612,
+ height: 792
+ }
+};
\ No newline at end of file
diff --git a/public/functions/splitPDF.js b/public/functions/splitPDF.js
new file mode 100644
index 000000000..dac378ce1
--- /dev/null
+++ b/public/functions/splitPDF.js
@@ -0,0 +1,24 @@
+import { createSubDocument } from "./extractPages.js";
+
+export async function splitPDF(snapshot, splitAfterPageArray, PDFLib) {
+ const pdfDoc = await PDFLib.PDFDocument.load(snapshot)
+
+ const numberOfPages = pdfDoc.getPages().length;
+
+ let pagesArray = [];
+ let splitAfter = splitAfterPageArray.shift();
+ const subDocuments = [];
+
+ for (let i = 0; i < numberOfPages; i++) {
+ if(i > splitAfter && pagesArray.length > 0) {
+ subDocuments.push(await createSubDocument(pdfDoc, pagesArray, PDFLib));
+ splitAfter = splitAfterPageArray.shift();
+ pagesArray = [];
+ }
+ pagesArray.push(i);
+ }
+ subDocuments.push(await createSubDocument(pdfDoc, pagesArray, PDFLib));
+ pagesArray = [];
+
+ return subDocuments;
+};
\ No newline at end of file
diff --git a/public/index.css b/public/index.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 000000000..f1cf9669c
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+
+
+
+