From e42c8199b02e939743ced71d5767fbf72abe1c1f Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Tue, 20 May 2025 10:36:34 -0300 Subject: [PATCH 1/3] pdforge init --- .../generate-pdf-from-html.mjs | 71 ++++++++++++ .../generate-pdf-from-template.mjs | 72 ++++++++++++ components/pdforge/package.json | 2 +- components/pdforge/pdforge.app.mjs | 109 +++++++++++++++++- 4 files changed, 249 insertions(+), 5 deletions(-) create mode 100644 components/pdforge/actions/generate-pdf-from-html/generate-pdf-from-html.mjs create mode 100644 components/pdforge/actions/generate-pdf-from-template/generate-pdf-from-template.mjs diff --git a/components/pdforge/actions/generate-pdf-from-html/generate-pdf-from-html.mjs b/components/pdforge/actions/generate-pdf-from-html/generate-pdf-from-html.mjs new file mode 100644 index 0000000000000..4d44826856752 --- /dev/null +++ b/components/pdforge/actions/generate-pdf-from-html/generate-pdf-from-html.mjs @@ -0,0 +1,71 @@ +import pdforge from "../../pdforge.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "pdforge-generate-pdf-from-html", + name: "Generate PDF from HTML", + description: "Generate a PDF document from HTML content. [See the documentation](https://docs.pdforge.com)", + version: "0.0.{{ts}}", + type: "action", + props: { + pdforge, + html: { + propDefinition: [ + pdforge, + "html", + ], + }, + pdfParams: { + propDefinition: [ + pdforge, + "pdfParams", + ], + optional: true, + }, + convertToImage: { + propDefinition: [ + pdforge, + "convertToImage", + ], + optional: true, + }, + s3bucket: { + propDefinition: [ + pdforge, + "s3bucket", + ], + optional: true, + }, + s3key: { + propDefinition: [ + pdforge, + "s3key", + ], + optional: true, + }, + webhook: { + propDefinition: [ + pdforge, + "webhook", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pdforge.generatePDFfromHTML({ + html: this.html, + pdfParams: this.pdfParams, + convertToImage: this.convertToImage, + s3bucket: this.s3bucket, + s3key: this.s3key, + webhook: this.webhook, + }); + + const summary = this.webhook + ? `PDF generation initiated with request ID: ${response.requestId}.` + : `PDF generated successfully. Download it using signed URL: ${response.signedUrl}.`; + + $.export("$summary", summary); + return response; + }, +}; diff --git a/components/pdforge/actions/generate-pdf-from-template/generate-pdf-from-template.mjs b/components/pdforge/actions/generate-pdf-from-template/generate-pdf-from-template.mjs new file mode 100644 index 0000000000000..9ae3808663be1 --- /dev/null +++ b/components/pdforge/actions/generate-pdf-from-template/generate-pdf-from-template.mjs @@ -0,0 +1,72 @@ +import pdforge from "../../pdforge.app.mjs"; +import { axios } from "@pipedream/platform"; + +export default { + key: "pdforge-generate-pdf-from-template", + name: "Generate PDF from Template", + description: "Generate a document from a selected template. [See the documentation](https://docs.pdforge.com/pdfs-from-templates/synchronous-request)", + version: "0.0.{{ts}}", + type: "action", + props: { + pdforge, + templateId: { + propDefinition: [ + pdforge, + "templateId", + ], + }, + data: { + propDefinition: [ + pdforge, + "data", + ], + optional: true, + }, + convertToImage: { + propDefinition: [ + pdforge, + "convertToImage", + ], + optional: true, + }, + s3bucket: { + propDefinition: [ + pdforge, + "s3bucket", + ], + optional: true, + }, + s3key: { + propDefinition: [ + pdforge, + "s3key", + ], + optional: true, + }, + webhook: { + propDefinition: [ + pdforge, + "webhook", + ], + optional: true, + }, + }, + async run({ $ }) { + const response = await this.pdforge.generateDocumentFromTemplate({ + templateId: this.templateId, + data: this.data, + convertToImage: this.convertToImage, + s3bucket: this.s3bucket, + s3key: this.s3key, + webhook: this.webhook, + }); + + if (this.webhook) { + $.export("$summary", "Asynchronous request initiated. Await the webhook callback for completion."); + } else { + $.export("$summary", `PDF generated successfully from template ID: ${this.templateId}`); + } + + return response; + }, +}; diff --git a/components/pdforge/package.json b/components/pdforge/package.json index 2eacebda43e22..73efff51e102a 100644 --- a/components/pdforge/package.json +++ b/components/pdforge/package.json @@ -12,4 +12,4 @@ "publishConfig": { "access": "public" } -} \ No newline at end of file +} diff --git a/components/pdforge/pdforge.app.mjs b/components/pdforge/pdforge.app.mjs index 31a2f1a8c3883..412fd5040a9a2 100644 --- a/components/pdforge/pdforge.app.mjs +++ b/components/pdforge/pdforge.app.mjs @@ -1,11 +1,112 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "pdforge", - propDefinitions: {}, + propDefinitions: { + templateId: { + type: "string", + label: "Template ID", + description: "The ID of the template from which to generate the document", + }, + data: { + type: "object", + label: "Data", + description: "The object containing the variables for your PDF template", + optional: true, + }, + convertToImage: { + type: "boolean", + label: "Convert to Image", + description: "Whether to convert the PDF to a PNG image", + optional: true, + default: false, + }, + s3bucket: { + type: "string", + label: "S3 Bucket", + description: "The ID of the active S3 connection to store the generated file on", + optional: true, + }, + s3key: { + type: "string", + label: "S3 Key", + description: "The path and filename without extension for saving the file in the S3 bucket", + optional: true, + }, + webhook: { + type: "string", + label: "Webhook URL", + description: "The URL of your webhook endpoint", + optional: true, + }, + html: { + type: "string", + label: "HTML", + description: "The HTML content you want to render as PDF", + }, + pdfParams: { + type: "object", + label: "PDF Parameters", + description: "PDF parameters to customize the output", + optional: true, + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.pdforge.com/v1"; + }, + async _makeRequest(opts = {}) { + const { + $ = this, method = "POST", path, headers, ...otherOpts + } = opts; + return axios($, { + ...otherOpts, + method, + url: this._baseUrl() + path, + headers: { + ...headers, + Authorization: `Bearer ${this.$auth.apiToken}`, + }, + }); + }, + async generateDocumentFromTemplate(opts = {}) { + const { + templateId, data, convertToImage, s3bucket, s3key, webhook, + } = opts; + const path = webhook + ? "/pdf/async" + : "/pdf/sync"; + return this._makeRequest({ + path, + data: { + templateId, + data, + convertToImage, + s3_bucket: s3bucket, + s3_key: s3key, + webhook, + }, + }); + }, + async generatePDFfromHTML(opts = {}) { + const { + html, pdfParams, convertToImage, s3bucket, s3key, webhook, + } = opts; + const path = webhook + ? "/html-to-pdf/async" + : "/html-to-pdf/sync"; + return this._makeRequest({ + path, + data: { + html, + pdfParams, + convertToImage, + s3_bucket: s3bucket, + s3_key: s3key, + webhook, + }, + }); }, }, }; From 9427bf63860cb0554e5ee0709eeb8a10bdfbc6ef Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 21 May 2025 14:54:07 -0300 Subject: [PATCH 2/3] [Components] pdforge #16687 Actions - Generate PDF From HTML - Generate PDF From TEMPLATE --- components/pdforge/actions/common/base.mjs | 134 ++++++++++++++++++ .../generate-pdf-from-html.mjs | 80 ++++------- .../generate-pdf-from-template.mjs | 80 ++++------- components/pdforge/common/utils.mjs | 48 +++++++ components/pdforge/package.json | 7 +- components/pdforge/pdforge.app.mjs | 114 +++++---------- 6 files changed, 274 insertions(+), 189 deletions(-) create mode 100644 components/pdforge/actions/common/base.mjs create mode 100644 components/pdforge/common/utils.mjs diff --git a/components/pdforge/actions/common/base.mjs b/components/pdforge/actions/common/base.mjs new file mode 100644 index 0000000000000..6ee73d9504022 --- /dev/null +++ b/components/pdforge/actions/common/base.mjs @@ -0,0 +1,134 @@ +import fs from "fs"; +import stream from "stream"; +import { promisify } from "util"; +import { + checkTmp, + clearObj, +} from "../../common/utils.mjs"; +import pdforge from "../../pdforge.app.mjs"; + +export default { + props: { + pdforge, + convertToImage: { + type: "boolean", + label: "Convert to Image", + description: "If true, will return a .PNG file instead of a .PDF file", + default: false, + }, + asyncMode: { + type: "boolean", + label: "Async Mode", + description: "If `true`, the request will be executed in the background and the response will be sent to the webhook URL.", + default: false, + reloadProps: true, + }, + saveS3: { + type: "boolean", + label: "Save to S3", + description: "If `true`, the generated file will be saved to the provided s3 bucket; if `false`, the generated file will be saved to the Pipedream `/tmp` directory.", + default: true, + reloadProps: true, + hidden: true, + }, + s3bucket: { + propDefinition: [ + pdforge, + "s3bucket", + ], + hidden: true, + }, + s3key: { + propDefinition: [ + pdforge, + "s3key", + ], + hidden: true, + }, + fileName: { + propDefinition: [ + pdforge, + "fileName", + ], + hidden: true, + }, + webhook: { + propDefinition: [ + pdforge, + "webhook", + ], + hidden: true, + }, + }, + async additionalProps(props) { + const isAsync = this.asyncMode; + const saveAtS3 = this.saveS3; + + props.webhook.hidden = !isAsync; + props.saveS3.hidden = isAsync; + + const showS3 = !isAsync && saveAtS3; + props.s3bucket.hidden = !showS3; + props.s3key.hidden = !showS3; + props.fileName.hidden = showS3; + return {}; + }, + async run({ $ }) { + let response; + + const data = { + ...this.getAdditionalData(), + convertToImage: this.convertToImage, + webhook: this.webhook, + }; + + if (this.saveS3) { + data.s3Bucked = this.s3Bucked; + data.s3Key = this.s3Key; + } + + if (this.asyncMode) { + data.webhook = this.webhook; + } + + const fn = this.getFunction(); + + const asyncResponse = await fn({ + $, + asyncMode: this.asyncMode, + data: clearObj(data), + }); + + response = asyncResponse; + + if (!this.saveS3 && !this.asyncMode) { + const fileStream = await this.pdforge._makeRequest({ + baseUrl: response.signedUrl, + responseType: "stream", + removeHeader: true, + }); + + const filePath = checkTmp( + `${this.fileName}.${this.convertToImage + ? "PNG" + : "PDF"}`, + ); + + const pipeline = promisify(stream.pipeline); + await pipeline(fileStream, fs.createWriteStream(filePath)); + + response = { + ...asyncResponse, + filePath, + }; + } + + if (this.asyncMode) { + $.export("$summary", "Asynchronous request initiated. Await the webhook callback for completion."); + } else { + $.export("$summary", this.getSummary(this)); + } + + return response; + }, +}; diff --git a/components/pdforge/actions/generate-pdf-from-html/generate-pdf-from-html.mjs b/components/pdforge/actions/generate-pdf-from-html/generate-pdf-from-html.mjs index 4d44826856752..a233c4efc63a3 100644 --- a/components/pdforge/actions/generate-pdf-from-html/generate-pdf-from-html.mjs +++ b/components/pdforge/actions/generate-pdf-from-html/generate-pdf-from-html.mjs @@ -1,71 +1,41 @@ -import pdforge from "../../pdforge.app.mjs"; -import { axios } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; +import common from "../common/base.mjs"; export default { + ...common, key: "pdforge-generate-pdf-from-html", name: "Generate PDF from HTML", - description: "Generate a PDF document from HTML content. [See the documentation](https://docs.pdforge.com)", - version: "0.0.{{ts}}", + description: "Generate a PDF document from HTML content. [See the documentation](https://docs.pdforge.com/html-to-pdf-conversion/synchronous-request)", + version: "0.0.1", type: "action", props: { - pdforge, + ...common.props, html: { - propDefinition: [ - pdforge, - "html", - ], + type: "string", + label: "HTML", + description: "The HTML content you want to render", }, pdfParams: { - propDefinition: [ - pdforge, - "pdfParams", - ], + type: "object", + label: "PDF Params", + description: "The object containing the parameters for your PDF. [See all the options here](https://docs.pdforge.com/options/pdf-params).", optional: true, }, - convertToImage: { - propDefinition: [ - pdforge, - "convertToImage", - ], - optional: true, + }, + methods: { + getAdditionalData() { + return { + html: this.html, + pdfParams: parseObject(this.pdfParams), + }; }, - s3bucket: { - propDefinition: [ - pdforge, - "s3bucket", - ], - optional: true, + getFunction() { + return this.pdforge.generatePDFfromHTML; }, - s3key: { - propDefinition: [ - pdforge, - "s3key", - ], - optional: true, + getSummary({ convertToImage }) { + return `${convertToImage + ? "PNG" + : "PDF"} successfully generated from provided HTML content.`; }, - webhook: { - propDefinition: [ - pdforge, - "webhook", - ], - optional: true, - }, - }, - async run({ $ }) { - const response = await this.pdforge.generatePDFfromHTML({ - html: this.html, - pdfParams: this.pdfParams, - convertToImage: this.convertToImage, - s3bucket: this.s3bucket, - s3key: this.s3key, - webhook: this.webhook, - }); - - const summary = this.webhook - ? `PDF generation initiated with request ID: ${response.requestId}.` - : `PDF generated successfully. Download it using signed URL: ${response.signedUrl}.`; - - $.export("$summary", summary); - return response; }, }; diff --git a/components/pdforge/actions/generate-pdf-from-template/generate-pdf-from-template.mjs b/components/pdforge/actions/generate-pdf-from-template/generate-pdf-from-template.mjs index 9ae3808663be1..b11f68c4e831d 100644 --- a/components/pdforge/actions/generate-pdf-from-template/generate-pdf-from-template.mjs +++ b/components/pdforge/actions/generate-pdf-from-template/generate-pdf-from-template.mjs @@ -1,72 +1,40 @@ -import pdforge from "../../pdforge.app.mjs"; -import { axios } from "@pipedream/platform"; +import { parseObject } from "../../common/utils.mjs"; +import common from "../common/base.mjs"; export default { + ...common, key: "pdforge-generate-pdf-from-template", name: "Generate PDF from Template", description: "Generate a document from a selected template. [See the documentation](https://docs.pdforge.com/pdfs-from-templates/synchronous-request)", - version: "0.0.{{ts}}", + version: "0.0.1", type: "action", props: { - pdforge, + ...common.props, templateId: { - propDefinition: [ - pdforge, - "templateId", - ], + type: "string", + label: "Template ID", + description: "The ID of the template from which to generate the document", }, data: { - propDefinition: [ - pdforge, - "data", - ], - optional: true, + type: "object", + label: "Data", + description: "The object containing the variables for your PDF template", }, - convertToImage: { - propDefinition: [ - pdforge, - "convertToImage", - ], - optional: true, - }, - s3bucket: { - propDefinition: [ - pdforge, - "s3bucket", - ], - optional: true, + }, + methods: { + getAdditionalData() { + return { + templateId: this.templateId, + data: parseObject(this.data), + }; }, - s3key: { - propDefinition: [ - pdforge, - "s3key", - ], - optional: true, + getFunction() { + return this.pdforge.generateDocumentFromTemplate; }, - webhook: { - propDefinition: [ - pdforge, - "webhook", - ], - optional: true, + getSummary({ convertToImage }) { + return `${convertToImage + ? "PNG" + : "PDF"} generated successfully from template ID: ${this.templateId}`; }, }, - async run({ $ }) { - const response = await this.pdforge.generateDocumentFromTemplate({ - templateId: this.templateId, - data: this.data, - convertToImage: this.convertToImage, - s3bucket: this.s3bucket, - s3key: this.s3key, - webhook: this.webhook, - }); - - if (this.webhook) { - $.export("$summary", "Asynchronous request initiated. Await the webhook callback for completion."); - } else { - $.export("$summary", `PDF generated successfully from template ID: ${this.templateId}`); - } - - return response; - }, }; diff --git a/components/pdforge/common/utils.mjs b/components/pdforge/common/utils.mjs new file mode 100644 index 0000000000000..9420d92839d7d --- /dev/null +++ b/components/pdforge/common/utils.mjs @@ -0,0 +1,48 @@ +export const checkTmp = (filename) => { + if (!filename.startsWith("/tmp")) { + return `/tmp/${filename}`; + } + return filename; +}; + +export const parseObject = (obj) => { + if (!obj) return undefined; + + if (Array.isArray(obj)) { + return obj.map((item) => { + if (typeof item === "string") { + try { + return JSON.parse(item); + } catch (e) { + return item; + } + } + return item; + }); + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch (e) { + return obj; + } + } + return obj; +}; + +export const clearObj = (obj) => { + return Object.entries(obj) + .filter(([ + , + v, + ]) => (v != null && v != "" && JSON.stringify(v) != "{}")) + .reduce((acc, [ + k, + v, + ]) => ({ + ...acc, + [k]: (!Array.isArray(v) && v === Object(v)) + ? clearObj(v) + : v, + }), {}); +}; diff --git a/components/pdforge/package.json b/components/pdforge/package.json index 73efff51e102a..58340b2703626 100644 --- a/components/pdforge/package.json +++ b/components/pdforge/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/pdforge", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream pdforge Components", "main": "pdforge.app.mjs", "keywords": [ @@ -11,5 +11,10 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.0.3", + "stream": "^0.0.3", + "util": "^0.12.5" } } diff --git a/components/pdforge/pdforge.app.mjs b/components/pdforge/pdforge.app.mjs index 412fd5040a9a2..e4a2e9f6deda9 100644 --- a/components/pdforge/pdforge.app.mjs +++ b/components/pdforge/pdforge.app.mjs @@ -4,108 +4,68 @@ export default { type: "app", app: "pdforge", propDefinitions: { - templateId: { - type: "string", - label: "Template ID", - description: "The ID of the template from which to generate the document", - }, - data: { - type: "object", - label: "Data", - description: "The object containing the variables for your PDF template", - optional: true, - }, - convertToImage: { - type: "boolean", - label: "Convert to Image", - description: "Whether to convert the PDF to a PNG image", - optional: true, - default: false, - }, s3bucket: { type: "string", label: "S3 Bucket", description: "The ID of the active S3 connection to store the generated file on", - optional: true, }, s3key: { type: "string", label: "S3 Key", description: "The path and filename without extension for saving the file in the S3 bucket", - optional: true, + secret: true, + }, + fileName: { + type: "string", + label: "File Name", + description: "The filename without extension for saving the file in the `/tmp` direcrtory", }, webhook: { type: "string", label: "Webhook URL", description: "The URL of your webhook endpoint", - optional: true, - }, - html: { - type: "string", - label: "HTML", - description: "The HTML content you want to render as PDF", - }, - pdfParams: { - type: "object", - label: "PDF Parameters", - description: "PDF parameters to customize the output", - optional: true, }, }, methods: { - _baseUrl() { - return "https://api.pdforge.com/v1"; + _baseUrl(baseUrl) { + return baseUrl || "https://api.pdforge.com/v1"; + }, + _headers(removeHeader = false) { + return removeHeader + ? {} + : { + Authorization: `Bearer ${this.$auth.api_key}`, + }; }, - async _makeRequest(opts = {}) { - const { - $ = this, method = "POST", path, headers, ...otherOpts - } = opts; + _makeRequest({ + $ = this, baseUrl, removeHeader, path = "", ...opts + }) { return axios($, { - ...otherOpts, - method, - url: this._baseUrl() + path, - headers: { - ...headers, - Authorization: `Bearer ${this.$auth.apiToken}`, - }, + url: this._baseUrl(baseUrl) + path, + headers: this._headers(removeHeader), + ...opts, }); }, - async generateDocumentFromTemplate(opts = {}) { - const { - templateId, data, convertToImage, s3bucket, s3key, webhook, - } = opts; - const path = webhook - ? "/pdf/async" - : "/pdf/sync"; + generateDocumentFromTemplate({ + asyncMode, ...opts + }) { return this._makeRequest({ - path, - data: { - templateId, - data, - convertToImage, - s3_bucket: s3bucket, - s3_key: s3key, - webhook, - }, + method: "POST", + path: `/pdf/${asyncMode + ? "async" + : "sync"}`, + ...opts, }); }, - async generatePDFfromHTML(opts = {}) { - const { - html, pdfParams, convertToImage, s3bucket, s3key, webhook, - } = opts; - const path = webhook - ? "/html-to-pdf/async" - : "/html-to-pdf/sync"; + generatePDFfromHTML({ + asyncMode, ...opts + }) { return this._makeRequest({ - path, - data: { - html, - pdfParams, - convertToImage, - s3_bucket: s3bucket, - s3_key: s3key, - webhook, - }, + method: "POST", + path: `/html-to-pdf/${asyncMode + ? "async" + : "sync"}`, + ...opts, }); }, }, From 0da3fefb60acee636cce73c6e87a5b171c2b52c0 Mon Sep 17 00:00:00 2001 From: Luan Cazarine Date: Wed, 21 May 2025 14:55:27 -0300 Subject: [PATCH 3/3] pnpm update --- pnpm-lock.yaml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c1a50a7626a9..382bab8f38873 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9604,7 +9604,17 @@ importers: specifier: ^3.0.3 version: 3.0.3 - components/pdforge: {} + components/pdforge: + dependencies: + '@pipedream/platform': + specifier: ^3.0.3 + version: 3.0.3 + stream: + specifier: ^0.0.3 + version: 0.0.3 + util: + specifier: ^0.12.5 + version: 0.12.5 components/peach: dependencies: @@ -15404,14 +15414,6 @@ importers: specifier: ^6.0.0 version: 6.2.0 - modelcontextprotocol/node_modules2/@modelcontextprotocol/sdk/dist/cjs: {} - - modelcontextprotocol/node_modules2/@modelcontextprotocol/sdk/dist/esm: {} - - modelcontextprotocol/node_modules2/zod-to-json-schema/dist/cjs: {} - - modelcontextprotocol/node_modules2/zod-to-json-schema/dist/esm: {} - packages/ai: dependencies: '@pipedream/sdk':