n8n-nodes-quickpdf 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Quick PDF Tools
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,65 @@
1
- # Temporary Holding Version
1
+ # n8n-nodes-quickpdf
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Community package for [Quick PDF Tools API v1](https://quickpdftools.net/developers/) — **Unlock**, **Protect**, and **Repair** on n8n Cloud (no `qpdf` on the host).
4
+
5
+ | Operation | API route |
6
+ |-----------|-----------|
7
+ | Unlock | `POST /api/v1/pdf/unlock` |
8
+ | Protect | `POST /api/v1/pdf/protect` |
9
+ | Repair | `POST /api/v1/pdf/repair` |
10
+
11
+ Guide: https://quickpdftools.net/developers/n8n/
12
+
13
+ ## Build
14
+
15
+ ```bash
16
+ npm install --ignore-scripts
17
+ npm run build
18
+ npm run validate
19
+ ```
20
+
21
+ ## Install in n8n
22
+
23
+ **Cloud:** Settings → Community nodes → Install → `n8n-nodes-quickpdf` (after `npm publish`).
24
+
25
+ **Self-hosted / dev:**
26
+
27
+ ```bash
28
+ npm link
29
+ # In n8n user folder or custom directory:
30
+ npm link n8n-nodes-quickpdf
31
+ ```
32
+
33
+ Restart n8n, then add **Quick PDF Tools** from the node panel.
34
+
35
+ ## Credential
36
+
37
+ | Field | Value |
38
+ |-------|--------|
39
+ | API Key | `qpdf_live_…` from [developers portal](https://quickpdftools.net/developers/#keys) |
40
+ | API Base URL | Default `https://api.quickpdftools.net` |
41
+
42
+ ## Node parameters
43
+
44
+ - **Operation** — unlock / protect / repair
45
+ - **Binary Property** — input PDF (default `data`)
46
+ - **Password** — required for unlock & protect
47
+ - **Output Binary Property** — decrypted PDF (default `data`)
48
+
49
+ ## Test
50
+
51
+ 1. Load CC0 [`locked.pdf`](https://quickpdftools.net/developers/oss/fixtures/locked.pdf) into binary `data`.
52
+ 2. **Quick PDF Tools** → Unlock, password `secret123`.
53
+ 3. Open output PDF in the next node or download.
54
+
55
+ ## Publish
56
+
57
+ See [COMMUNITY_SUBMISSION.md](./COMMUNITY_SUBMISSION.md).
58
+
59
+ ```bash
60
+ npm publish --access public
61
+ ```
62
+
63
+ ## License
64
+
65
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,17 @@
1
+ import type { ICredentialTestRequest, ICredentialType, INodeProperties } from "n8n-workflow";
2
+ export declare class QuickPdfApi implements ICredentialType {
3
+ name: string;
4
+ displayName: string;
5
+ documentationUrl: string;
6
+ supportedNodes: string[];
7
+ properties: INodeProperties[];
8
+ authenticate: {
9
+ type: "generic";
10
+ properties: {
11
+ headers: {
12
+ Authorization: string;
13
+ };
14
+ };
15
+ };
16
+ test: ICredentialTestRequest;
17
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QuickPdfApi = void 0;
4
+ class QuickPdfApi {
5
+ constructor() {
6
+ this.name = "quickPdfApi";
7
+ this.displayName = "Quick PDF Tools API";
8
+ this.documentationUrl = "https://quickpdftools.net/developers/";
9
+ this.supportedNodes = ["n8n-nodes-quickpdf.quickPdf"];
10
+ this.properties = [
11
+ {
12
+ displayName: "API Key",
13
+ name: "apiKey",
14
+ type: "string",
15
+ typeOptions: { password: true },
16
+ default: "",
17
+ required: true,
18
+ description: 'Bearer key starting with qpdf_live_ (from quickpdftools.net/developers)',
19
+ },
20
+ {
21
+ displayName: "API Base URL",
22
+ name: "apiBase",
23
+ type: "string",
24
+ default: "https://api.quickpdftools.net",
25
+ required: true,
26
+ description: "Override for staging or self-hosted API",
27
+ },
28
+ ];
29
+ this.authenticate = {
30
+ type: "generic",
31
+ properties: {
32
+ headers: {
33
+ Authorization: '=Bearer {{$credentials.apiKey}}',
34
+ },
35
+ },
36
+ };
37
+ this.test = {
38
+ request: {
39
+ baseURL: "={{$credentials.apiBase.replace(/\\/$/, '')}}",
40
+ url: "/api/v1/capabilities",
41
+ method: "GET",
42
+ },
43
+ };
44
+ }
45
+ }
46
+ exports.QuickPdfApi = QuickPdfApi;
@@ -0,0 +1,5 @@
1
+ import type { IExecuteFunctions, INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
2
+ export declare class QuickPdf implements INodeType {
3
+ description: INodeTypeDescription;
4
+ execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
5
+ }
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.QuickPdf = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
5
+ class QuickPdf {
6
+ constructor() {
7
+ this.description = {
8
+ displayName: "Quick PDF Tools",
9
+ name: "quickPdf",
10
+ icon: "file:quickpdf.svg",
11
+ group: ["transform"],
12
+ version: [1],
13
+ subtitle: '={{$parameter["operation"]}}',
14
+ description: "Server-side PDF unlock, protect, and repair (Quick PDF Tools API v1)",
15
+ defaults: { name: "Quick PDF" },
16
+ inputs: ["main" /* NodeConnectionType.Main */],
17
+ outputs: ["main" /* NodeConnectionType.Main */],
18
+ credentials: [{ name: "quickPdfApi", required: true }],
19
+ properties: [
20
+ {
21
+ displayName: "Resource",
22
+ name: "resource",
23
+ type: "options",
24
+ noDataExpression: true,
25
+ options: [
26
+ {
27
+ name: "Document",
28
+ value: "document",
29
+ description: "PDF file operations via Quick PDF Tools API",
30
+ },
31
+ ],
32
+ default: "document",
33
+ required: true,
34
+ },
35
+ {
36
+ displayName: "Operation",
37
+ name: "operation",
38
+ type: "options",
39
+ noDataExpression: true,
40
+ displayOptions: {
41
+ show: {
42
+ resource: ["document"],
43
+ },
44
+ },
45
+ options: [
46
+ { name: "Unlock", value: "unlock", action: "Unlock a PDF with a known password" },
47
+ { name: "Protect", value: "protect", action: "Encrypt a PDF with a password" },
48
+ { name: "Repair", value: "repair", action: "Repair damaged PDF structure" },
49
+ ],
50
+ default: "unlock",
51
+ required: true,
52
+ },
53
+ {
54
+ displayName: "Binary Property",
55
+ name: "binaryPropertyName",
56
+ type: "string",
57
+ default: "data",
58
+ displayOptions: {
59
+ show: {
60
+ resource: ["document"],
61
+ },
62
+ },
63
+ description: "Input PDF binary field from the previous node",
64
+ },
65
+ {
66
+ displayName: "Password",
67
+ name: "password",
68
+ type: "string",
69
+ typeOptions: { password: true },
70
+ default: "",
71
+ required: true,
72
+ displayOptions: {
73
+ show: {
74
+ resource: ["document"],
75
+ operation: ["unlock", "protect"],
76
+ },
77
+ },
78
+ description: "Password for unlock or protect",
79
+ },
80
+ {
81
+ displayName: "Output Binary Property",
82
+ name: "outputBinaryPropertyName",
83
+ type: "string",
84
+ default: "data",
85
+ displayOptions: {
86
+ show: {
87
+ resource: ["document"],
88
+ },
89
+ },
90
+ description: "Where to write the resulting PDF bytes",
91
+ },
92
+ ],
93
+ };
94
+ }
95
+ async execute() {
96
+ var _a, _b;
97
+ const items = this.getInputData();
98
+ const returnData = [];
99
+ const credentials = await this.getCredentials("quickPdfApi");
100
+ const apiBase = String(credentials.apiBase || "https://api.quickpdftools.net").replace(/\/$/, "");
101
+ const apiKey = String(credentials.apiKey || "");
102
+ for (let i = 0; i < items.length; i++) {
103
+ try {
104
+ const resource = this.getNodeParameter("resource", i);
105
+ if (resource !== "document") {
106
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: `Unknown resource "${resource}"` });
107
+ }
108
+ const operation = this.getNodeParameter("operation", i);
109
+ const binaryPropertyName = this.getNodeParameter("binaryPropertyName", i);
110
+ const outputBinaryPropertyName = this.getNodeParameter("outputBinaryPropertyName", i);
111
+ const binary = (_a = items[i].binary) === null || _a === void 0 ? void 0 : _a[binaryPropertyName];
112
+ if (!(binary === null || binary === void 0 ? void 0 : binary.data)) {
113
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), {
114
+ message: `No binary data on property "${binaryPropertyName}"`,
115
+ });
116
+ }
117
+ const buffer = Buffer.from(binary.data, "base64");
118
+ const form = new FormData();
119
+ const mime = binary.mimeType || "application/pdf";
120
+ form.append("file", new Blob([buffer], { type: mime }), binary.fileName || "document.pdf");
121
+ if (operation !== "repair") {
122
+ const password = this.getNodeParameter("password", i);
123
+ if (!password) {
124
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), { message: "Password is required for this operation" });
125
+ }
126
+ form.append("password", password);
127
+ }
128
+ const response = await this.helpers.httpRequest({
129
+ method: "POST",
130
+ url: `${apiBase}/api/v1/pdf/${operation}`,
131
+ headers: {
132
+ Authorization: `Bearer ${apiKey}`,
133
+ },
134
+ body: form,
135
+ encoding: "arraybuffer",
136
+ returnFullResponse: true,
137
+ json: false,
138
+ });
139
+ const statusCode = Number(response.statusCode || 0);
140
+ const body = Buffer.isBuffer(response.body)
141
+ ? response.body
142
+ : Buffer.from(response.body);
143
+ const contentType = String(((_b = response.headers) === null || _b === void 0 ? void 0 : _b["content-type"]) || "").toLowerCase();
144
+ if (statusCode >= 400 || contentType.includes("application/json")) {
145
+ let message = `Quick PDF API error (${statusCode || "unknown"})`;
146
+ try {
147
+ const j = JSON.parse(body.toString("utf8"));
148
+ message = j.error || j.code || message;
149
+ }
150
+ catch {
151
+ /* non-JSON body */
152
+ }
153
+ throw new n8n_workflow_1.NodeApiError(this.getNode(), { message });
154
+ }
155
+ const outName = operation === "unlock"
156
+ ? (binary.fileName || "document.pdf").replace(/\.pdf$/i, "-unlocked.pdf")
157
+ : operation === "protect"
158
+ ? (binary.fileName || "document.pdf").replace(/\.pdf$/i, "-protected.pdf")
159
+ : (binary.fileName || "document.pdf").replace(/\.pdf$/i, "-repaired.pdf");
160
+ const newItem = {
161
+ json: {
162
+ ...items[i].json,
163
+ quickPdf: { resource, operation, apiBase, bytes: body.length },
164
+ },
165
+ binary: {
166
+ ...(items[i].binary || {}),
167
+ [outputBinaryPropertyName]: await this.helpers.prepareBinaryData(body, outName, "application/pdf"),
168
+ },
169
+ };
170
+ returnData.push(newItem);
171
+ }
172
+ catch (error) {
173
+ if (this.continueOnFail()) {
174
+ returnData.push({ json: { error: error.message }, pairedItem: { item: i } });
175
+ continue;
176
+ }
177
+ throw error;
178
+ }
179
+ }
180
+ return [returnData];
181
+ }
182
+ }
183
+ exports.QuickPdf = QuickPdf;
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Quick PDF">
2
+ <rect width="64" height="64" rx="14" fill="#ea4b71"/>
3
+ <path fill="#fff" d="M18 16h20l12 12v28H18V16zm20 2v10h10L38 18zM24 36h16v4H24v-4zm0 8h12v4H24v-4z"/>
4
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,57 @@
1
1
  {
2
2
  "name": "n8n-nodes-quickpdf",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "description": "Unlock, protect, and repair PDFs via Quick PDF Tools API v1 (n8n Cloud friendly — no qpdf on host)",
5
+ "keywords": [
6
+ "n8n-community-node-package",
7
+ "n8n",
8
+ "pdf",
9
+ "unlock",
10
+ "quickpdftools"
11
+ ],
12
+ "license": "MIT",
13
+ "homepage": "https://quickpdftools.net/developers/n8n/",
14
+ "author": {
15
+ "name": "Quick PDF Tools",
16
+ "url": "https://quickpdftools.net"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/ricksr/n8n-nodes-quickpdf.git"
21
+ },
22
+ "bugs": {
23
+ "url": "https://quickpdftools.net/contact.html"
24
+ },
25
+ "main": "index.js",
26
+ "scripts": {
27
+ "build": "tsc && gulp build:icons",
28
+ "dev": "tsc --watch",
29
+ "prepublishOnly": "npm run build",
30
+ "validate": "node scripts/validate-build.mjs"
31
+ },
32
+ "files": [
33
+ "dist"
34
+ ],
35
+ "n8n": {
36
+ "n8nNodesApiVersion": 1,
37
+ "strict": true,
38
+ "credentials": [
39
+ "dist/credentials/QuickPdfApi.credentials.js"
40
+ ],
41
+ "nodes": [
42
+ "dist/nodes/QuickPdf/QuickPdf.node.js"
43
+ ]
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^20.14.0",
47
+ "gulp": "^5.0.0",
48
+ "n8n-workflow": "^1.82.0",
49
+ "typescript": "^5.4.5"
50
+ },
51
+ "peerDependencies": {
52
+ "n8n-workflow": ">=1.0.0"
53
+ },
54
+ "engines": {
55
+ "node": ">=18.17.0"
56
+ }
6
57
  }