mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-02-02 00:16:34 +01:00
sync & async api
This commit is contained in:
parent
c60de02e14
commit
5203fc3605
52
README.md
52
README.md
@ -2,12 +2,54 @@
|
||||
|
||||
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.
|
||||
|
||||
## New/Planned Features
|
||||
## Features
|
||||
|
||||
- Propper auth using passportjs
|
||||
- Workflows & Node based editing of them.
|
||||
- Client side PDF-Manipulation
|
||||
- Stateful UI
|
||||
### New
|
||||
|
||||
[ ] Propper auth using passportjs
|
||||
[x] Workflows
|
||||
[ ] Node based editing of them.
|
||||
[x] Client side PDF-Manipulation
|
||||
[ ] Stateful UI
|
||||
|
||||
### Functions
|
||||
|
||||
Current functions of spdf and their progress in this repo.
|
||||
|
||||
[x] Merge
|
||||
[x] Split
|
||||
[x] Rotate
|
||||
[x] Multi-Page-Layout
|
||||
[x] Adjust page size/scale
|
||||
[ ] Organize
|
||||
[ ] Change Metadata
|
||||
[ ] Add Watermark
|
||||
|
||||
[ ] Remove Pages
|
||||
[ ] Remove Blank Pages
|
||||
[ ] Detect/Split Scanned photos
|
||||
|
||||
[ ] Repair
|
||||
[ ] Compress
|
||||
[ ] Flatten
|
||||
[ ] Compare/Diff
|
||||
|
||||
[ ] Sign
|
||||
[ ] Sign with Certificate
|
||||
[ ] Add Password
|
||||
[ ] Remove Password
|
||||
[ ] Change Permissions
|
||||
|
||||
[ ] Image to PDF
|
||||
[ ] Add image
|
||||
[ ] Extract Images
|
||||
[ ] PDF to Image
|
||||
[ ] OCR
|
||||
|
||||
[ ] Convert file to PDF
|
||||
[ ] PDF to Text/RTF
|
||||
[ ] PDF to HTML
|
||||
[ ] PDF to XML
|
||||
|
||||
## Contribute
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
// TODO: Make API endpoints available
|
4
index.js
4
index.js
@ -1,4 +1,6 @@
|
||||
|
||||
import api from './routes/api/index.js';
|
||||
|
||||
import express from 'express';
|
||||
const app = express();
|
||||
const PORT = 8080;
|
||||
@ -10,7 +12,7 @@ app.get('/', function (req, res, next) { // TODO: Use EJS?
|
||||
res.render('home.ejs');
|
||||
});
|
||||
|
||||
// TODO: Import and server /api
|
||||
app.use("/api/", api);
|
||||
|
||||
app.listen(PORT, function (err) {
|
||||
if (err) console.log(err);
|
||||
|
276
package-lock.json
generated
276
package-lock.json
generated
@ -4,6 +4,32 @@
|
||||
"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",
|
||||
@ -13,11 +39,31 @@
|
||||
"negotiator": "0.6.3"
|
||||
}
|
||||
},
|
||||
"append-field": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
|
||||
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"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",
|
||||
@ -37,6 +83,28 @@
|
||||
"unpipe": "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-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=="
|
||||
},
|
||||
"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",
|
||||
@ -51,6 +119,46 @@
|
||||
"get-intrinsic": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^2.2.2",
|
||||
"typedarray": "^0.0.6"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@ -74,6 +182,11 @@
|
||||
"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=="
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
@ -102,6 +215,14 @@
|
||||
"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",
|
||||
@ -150,6 +271,11 @@
|
||||
"vary": "~1.1.2"
|
||||
}
|
||||
},
|
||||
"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=="
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
@ -174,6 +300,16 @@
|
||||
"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=="
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@ -225,6 +361,11 @@
|
||||
"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=="
|
||||
},
|
||||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
@ -235,11 +376,25 @@
|
||||
"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=="
|
||||
},
|
||||
"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",
|
||||
@ -268,16 +423,48 @@
|
||||
"mime-db": "1.52.0"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.6"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"multer": {
|
||||
"version": "1.4.5-lts.1",
|
||||
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
|
||||
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
|
||||
"requires": {
|
||||
"append-field": "^1.0.0",
|
||||
"busboy": "^1.0.0",
|
||||
"concat-stream": "^1.5.2",
|
||||
"mkdirp": "^0.5.4",
|
||||
"object-assign": "^4.1.1",
|
||||
"type-is": "^1.6.4",
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz",
|
||||
@ -291,6 +478,19 @@
|
||||
"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",
|
||||
@ -301,6 +501,22 @@
|
||||
"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",
|
||||
@ -334,6 +550,16 @@
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
@ -402,11 +628,41 @@
|
||||
"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=="
|
||||
},
|
||||
"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",
|
||||
@ -416,11 +672,21 @@
|
||||
"mime-types": "~2.1.24"
|
||||
}
|
||||
},
|
||||
"typedarray": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
|
||||
},
|
||||
"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",
|
||||
@ -430,6 +696,16 @@
|
||||
"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=="
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,10 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"express": "^4.18.2"
|
||||
"@wasmer/wasmfs": "^0.12.0",
|
||||
"express": "^4.18.2",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"pdf-lib": "^1.17.1"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
12
routes/api/index.js
Normal file
12
routes/api/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
import express from 'express';
|
||||
import workflow from './workflow.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/", function (req, res, next) {
|
||||
res.status(501).json({"Error": "Unfinished Endpoint"});
|
||||
});
|
||||
|
||||
router.use("/workflow", workflow);
|
||||
|
||||
export default router;
|
125
routes/api/workflow.js
Normal file
125
routes/api/workflow.js
Normal file
@ -0,0 +1,125 @@
|
||||
import express from 'express';
|
||||
import multer from 'multer';
|
||||
import crypto from 'crypto';
|
||||
import stream from "stream";
|
||||
|
||||
import { traverseOperations } from "../../traverseOperations.js";
|
||||
|
||||
const activeWorkflows = {};
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.post("/", [
|
||||
multer().array("files"),
|
||||
async (req, res, next) => {
|
||||
const workflow = JSON.parse(req.body.workflow);
|
||||
console.log("fileCount: ", req.files.length);
|
||||
console.log("workflow: ", workflow);
|
||||
|
||||
// TODO: Validate
|
||||
|
||||
let workflowID = undefined;
|
||||
|
||||
const inputs = await Promise.all(req.files.map(async file => {
|
||||
console.log(file);
|
||||
return {
|
||||
originalFileName: file.originalname.replace(/\.[^/.]+$/, ""),
|
||||
fileName: file.originalname.replace(/\.[^/.]+$/, ""),
|
||||
buffer: new Uint8Array(await file.buffer)
|
||||
}
|
||||
}));
|
||||
|
||||
// Allow option to do it synchronously and just make a long request
|
||||
if(req.body.async === "false") {
|
||||
console.log("Don't do async");
|
||||
|
||||
const pdfResults = await traverseOperations(workflow.operations, inputs);
|
||||
downloadHandler(res, pdfResults);
|
||||
}
|
||||
else {
|
||||
workflowID = generateWorkflowID();
|
||||
activeWorkflows[workflowID] = {
|
||||
createdAt: Date.now(),
|
||||
finished: false,
|
||||
eventStream: null,
|
||||
result: null,
|
||||
// TODO: When auth is implemented: owner
|
||||
}
|
||||
|
||||
res.status(501).json({
|
||||
"warning": "Unfinished Endpoint",
|
||||
"workflowID": workflowID,
|
||||
"data-recieved": {
|
||||
"fileCount": req.files.length,
|
||||
"workflow": workflow
|
||||
}
|
||||
});
|
||||
|
||||
traverseOperations(workflow.operations, inputs).then((pdfResults) => {
|
||||
activeWorkflows[workflowID].result = pdfResults;
|
||||
activeWorkflows[workflowID].finished = true;
|
||||
// TODO: Post to eventStream
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
||||
router.get("/progress/:workflowUuid", (req, res, nex) => {
|
||||
// TODO: Validation
|
||||
|
||||
// Return current progress
|
||||
const workflow = activeWorkflows[req.params.workflowUuid];
|
||||
res.status(200).json({ createdAt: workflow.createdAt, finished: workflow.finished });
|
||||
});
|
||||
|
||||
router.get("/progress-stream/:workflowUuid", (req, res, nex) => {
|
||||
// TODO: Send realtime updates
|
||||
res.status(501).json({"warning": "Event-Stream has not been implemented yet."});
|
||||
});
|
||||
|
||||
router.get("/result/:workflowUuid", (req, res, nex) => {
|
||||
// TODO: Validation
|
||||
|
||||
/*
|
||||
* If workflow isn't done return error
|
||||
* Send file, TODO: if there are multiple outputs return as zip
|
||||
* If download is done, delete results / allow deletion within the next 5-60 mins
|
||||
*/
|
||||
const workflow = activeWorkflows[req.params.workflowUuid];
|
||||
if(!workflow.finished) {
|
||||
res.status(202).json({ message: "Workflow hasn't finished yet. Check progress or connect to progress-steam to get notified when its done." });
|
||||
return
|
||||
}
|
||||
|
||||
downloadHandler(res, workflow.result);
|
||||
// Delete workflow / results when done.
|
||||
delete activeWorkflows[req.params.workflowUuid];
|
||||
});
|
||||
|
||||
router.post("/abort/:workflowUuid", (req, res, nex) => {
|
||||
// TODO: Abort workflow
|
||||
res.status(501).json({"warning": "Abortion has not been implemented yet."});
|
||||
});
|
||||
|
||||
function generateWorkflowID() {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
|
||||
function downloadHandler(res, pdfResults) {
|
||||
if(pdfResults.length > 1) {
|
||||
res.status(501).json({"warning": "The workflow had multiple outputs, this is not implemented yet."});
|
||||
// TODO: Implement ZIP
|
||||
}
|
||||
else {
|
||||
const readStream = new stream.PassThrough();
|
||||
readStream.end(pdfResults[0].buffer);
|
||||
|
||||
// TODO: Implement other file types (mostly fro image & text extraction)
|
||||
res.set("Content-disposition", 'attachment; filename=' + pdfResults[0].fileName + ".pdf");
|
||||
res.set("Content-Type", "application/pdf");
|
||||
|
||||
readStream.pipe(res);
|
||||
}
|
||||
}
|
||||
|
||||
export default router;
|
206
traverseOperations.js
Normal file
206
traverseOperations.js
Normal file
@ -0,0 +1,206 @@
|
||||
import { extractPages } from "./functions/extractPages.js";
|
||||
import { impose } from "./functions/impose.js";
|
||||
import { mergePDFs } from "./functions/mergePDFs.js";
|
||||
import { rotatePages } from "./functions/rotatePDF.js";
|
||||
import { splitPDF } from "./functions/splitPDF.js";
|
||||
import { organizeWaitOperations } from "./public/organizeWaitOperations.js";
|
||||
|
||||
export async function traverseOperations(operations, input) {
|
||||
const waitOperations = organizeWaitOperations(operations);
|
||||
const results = [];
|
||||
await nextOperation(operations, input);
|
||||
return results;
|
||||
|
||||
async function nextOperation(operations, input) {
|
||||
if(Array.isArray(operations) && operations.length == 0) { // isEmpty
|
||||
console.log("operation done: " + input.fileName);
|
||||
results.push(input);
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < operations.length; i++) {
|
||||
await computeOperation(operations[i], structuredClone(input)); // break references
|
||||
}
|
||||
}
|
||||
|
||||
async function computeOperation(operation, input) {
|
||||
switch (operation.type) {
|
||||
case "done":
|
||||
console.log("Done operation will get called if all waits are done. Skipping for now.")
|
||||
break;
|
||||
case "wait":
|
||||
const waitOperation = waitOperations[operation.values.id];
|
||||
waitOperation.input.push(input);
|
||||
waitOperation.waitCount--;
|
||||
if(waitOperation.waitCount == 0) {
|
||||
await nextOperation(waitOperation.doneOperation.operations, waitOperation.input);
|
||||
}
|
||||
break;
|
||||
case "removeObjects":
|
||||
console.warn("RemoveObjects not implemented yet.")
|
||||
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
// TODO: modfiy input
|
||||
input[i].fileName += "_removedObjects";
|
||||
await nextOperation(operation.operations, input[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: modfiy input
|
||||
input.fileName += "_removedObjects";
|
||||
await nextOperation(operation.operations, input);
|
||||
}
|
||||
break;
|
||||
case "extract":
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
input[i].fileName += "_extractedPages";
|
||||
input[i].buffer = await extractPages(input[i].buffer, operation.values["pagesToExtractArray"]);
|
||||
await nextOperation(operation.operations, input[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
input.fileName += "_extractedPages";
|
||||
input.buffer = await extractPages(input.buffer, operation.values["pagesToExtractArray"]);
|
||||
await nextOperation(operation.operations, input);
|
||||
}
|
||||
break;
|
||||
case "split":
|
||||
// TODO: When a split goes into a wait function it might break the done condition, as it will count multiplpe times.
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const splits = await splitPDF(input[i].buffer, operation.values["pagesToSplitAfterArray"]);
|
||||
|
||||
for (let j = 0; j < splits.length; j++) {
|
||||
const split = {};
|
||||
split.originalFileName = input[i].originalFileName;
|
||||
split.fileName = input[i].fileName + "_split";
|
||||
split.buffer = splits[j];
|
||||
await nextOperation(operation.operations, split);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const splits = await splitPDF(input.buffer, operation.values["pagesToSplitAfterArray"]);
|
||||
|
||||
for (let j = 0; j < splits.length; j++) {
|
||||
const split = {};
|
||||
split.originalFileName = input.originalFileName;
|
||||
split.fileName = input.fileName + "_split";
|
||||
split.buffer = splits[j];
|
||||
await nextOperation(operation.operations, split);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "fillField":
|
||||
console.warn("FillField not implemented yet.")
|
||||
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
// TODO: modfiy input
|
||||
input[i].fileName += "_filledField";
|
||||
await nextOperation(operation.operations, input[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: modfiy input
|
||||
input.fileName += "_filledField";
|
||||
await nextOperation(operation.operations, input);
|
||||
}
|
||||
break;
|
||||
case "extractImages":
|
||||
console.warn("ExtractImages not implemented yet.")
|
||||
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
// TODO: modfiy input
|
||||
input[i].fileName += "_extractedImages";
|
||||
await nextOperation(operation.operations, input[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: modfiy input
|
||||
input.fileName += "_extractedImages";
|
||||
await nextOperation(operation.operations, input);
|
||||
}
|
||||
break;
|
||||
case "merge":
|
||||
if(Array.isArray(input) && input.length > 1) {
|
||||
const inputs = input;
|
||||
input = {
|
||||
originalFileName: inputs.map(input => input.originalFileName).join("_and_"),
|
||||
fileName: inputs.map(input => input.fileName).join("_and_") + "_merged",
|
||||
buffer: await mergePDFs(inputs.map(input => input.buffer))
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Only one input, no need to merge
|
||||
input.fileName += "_merged";
|
||||
}
|
||||
await nextOperation(operation.operations, input);
|
||||
break;
|
||||
case "transform": {
|
||||
console.warn("Transform not implemented yet.")
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
// TODO: modfiy input
|
||||
input[i].fileName += "_transformed";
|
||||
await nextOperation(operation.operations, input[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: modfiy input
|
||||
input.fileName += "_transformed";
|
||||
await nextOperation(operation.operations, input);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "extract":
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
input[i].fileName += "_extractedPages";
|
||||
input[i].buffer = await extractPages(input[i].buffer, operation.values["pagesToExtractArray"]);
|
||||
await nextOperation(operation.operations, input[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
input.fileName += "_extractedPages";
|
||||
input.buffer = await extractPages(input.buffer, operation.values["pagesToExtractArray"]);
|
||||
await nextOperation(operation.operations, input);
|
||||
}
|
||||
break;
|
||||
case "rotate":
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
input[i].fileName += "_turned";
|
||||
input[i].buffer = await rotatePages(input[i].buffer, operation.values["rotation"]);
|
||||
await nextOperation(operation.operations, input[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
input.fileName += "_turned";
|
||||
input.buffer = await rotatePages(input.buffer, operation.values["rotation"]);
|
||||
await nextOperation(operation.operations, input);
|
||||
}
|
||||
break;
|
||||
case "impose":
|
||||
if(Array.isArray(input)) {
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
input[i].fileName += "_imposed";
|
||||
input[i].buffer = await impose(input[i].buffer, operation.values["nup"], operation.values["format"]);
|
||||
await nextOperation(operation.operations, input[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
input.fileName += "_imposed";
|
||||
input.buffer = await impose(input.buffer, operation.values["nup"], operation.values["format"]);
|
||||
await nextOperation(operation.operations, input);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.log("operation type unknown: ", operation.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user