diff --git a/components/orshot/README.md b/components/orshot/README.md new file mode 100644 index 0000000000000..3b62fc37b6b52 --- /dev/null +++ b/components/orshot/README.md @@ -0,0 +1,107 @@ +# Orshot + +[Orshot](https://orshot.com) is an automated image generation API that allows you to generate dynamic images from pre-designed templates and AI-generated templates. + +## What is Orshot? + +Orshot enables developers and businesses to automatically generate images for: + +- [Website Screenshots](https://orshot.com/templates/website-screenshot) +- [Tweet Images](https://orshot.com/templates/tweet-image) +- Social media posts +- Marketing materials +- Dynamic content +- Personalized images + +With Orshot, you can create templates once and generate thousands of variations programmatically. + +## Authentication + +To use Orshot with Pipedream, you'll need an API key: + +1. Sign up at [Orshot](https://orshot.com) +2. Navigate to your Workspace → Settings → API Key +3. Copy your API key +4. Add it to your Pipedream workflow when connecting the Orshot app + +## Available Actions + +### Generate Image from Library Template + +Generate dynamic images using pre-designed templates from Orshot's template library. + +**Use Cases:** + +- Social media post generation +- Marketing material automation +- Dynamic content creation + +### Generate Image from Studio Template + +Generate images using custom templates created in Orshot Studio. + +**Use Cases:** + +- Brand-specific image generation +- Custom design automation +- Personalized content creation + +### List Templates + +Retrieve all available templates from your Orshot account. + +**Use Cases:** + +- Template discovery +- Dynamic template selection +- Workflow automation + +### Get Template Modifications + +Get available modification keys for a specific library template. + +**Use Cases:** + +- Dynamic form generation +- Template customization options +- Workflow configuration + +### Get Studio Template Modifications + +Get available modification keys for a specific studio template. + +**Use Cases:** + +- Custom template configuration +- Dynamic parameter discovery +- Advanced workflow setup + +## Response Formats + +Orshot supports multiple response formats: + +- **Base64**: Encoded image data for direct embedding +- **Binary**: Raw image data for file operations +- **URL**: Hosted image URL for immediate use + +## Supported Image Formats + +- PNG (default) +- JPG/JPEG +- WebP +- PDF + +## Example Use Cases + +1. **Social Media Automation**: Generate personalized social media posts based on user data +2. **E-commerce**: Create product images with dynamic pricing and offers +3. **Marketing Campaigns**: Generate campaign materials with personalized content +4. **Report Generation**: Create visual reports with dynamic charts and data +5. **Content Personalization**: Generate user-specific images for emails and websites + +## Links + +- [Orshot Website](https://orshot.com) +- [API Documentation](https://orshot.com/docs) +- [Template Library](https://orshot.com/templates) +- [Get API Key](https://orshot.com/workspace) diff --git a/components/orshot/actions/generate-image-library-template/generate-image-library-template.mjs b/components/orshot/actions/generate-image-library-template/generate-image-library-template.mjs new file mode 100644 index 0000000000000..59c3652a4ce0a --- /dev/null +++ b/components/orshot/actions/generate-image-library-template/generate-image-library-template.mjs @@ -0,0 +1,139 @@ +import orshot from "../../orshot.app.mjs"; +import { + getMimeType, parseObject, +} from "../../common/utils.mjs"; + +export default { + key: "orshot-generate-image-library-template", + name: "Generate Image from Library Template", + description: "Generate an image from a pre-designed library template using the Orshot API. [See the documentation](https://orshot.com/docs/api-reference/render-from-template)", + version: "0.0.1", + type: "action", + props: { + orshot, + templateId: { + propDefinition: [ + orshot, + "templateId", + ], + }, + responseType: { + propDefinition: [ + orshot, + "responseType", + ], + }, + responseFormat: { + propDefinition: [ + orshot, + "responseFormat", + ], + }, + modifications: { + propDefinition: [ + orshot, + "modifications", + ], + optional: true, + }, + }, + async run({ $ }) { + const { + templateId, + responseType, + responseFormat, + modifications = {}, + } = this; + + // Input validation + if (!templateId) { + throw new Error("Template ID is required"); + } + + if (!responseType) { + throw new Error("Response type is required"); + } + + if (!responseFormat) { + throw new Error("Response format is required"); + } + + // Validate responseType + const validResponseTypes = [ + "base64", + "binary", + "url", + ]; + if (!validResponseTypes.includes(responseType)) { + throw new Error( + `Invalid response type. Must be one of: ${validResponseTypes.join( + ", ", + )}`, + ); + } + + // Validate responseFormat + const validFormats = [ + "png", + "jpg", + "jpeg", + "webp", + ]; + if (!validFormats.includes(responseFormat.toLowerCase())) { + throw new Error( + `Invalid response format. Must be one of: ${validFormats.join(", ")}`, + ); + } + + const validModifications = parseObject(modifications); + + try { + const response = await this.orshot.generateImageFromLibraryTemplate({ + $, + data: { + templateId, + modifications: validModifications, + response: { + type: responseType, + format: responseFormat, + }, + }, + }); + + const result = { + templateId, + responseType, + responseFormat, + modifications: validModifications, + timestamp: new Date().toISOString(), + source: "orshot-pipedream", + }; + + // Handle different response types + switch (responseType) { + case "base64": + result.data = response.data; + result.mimeType = getMimeType(responseFormat); + break; + case "binary": + result.data = response; + result.mimeType = getMimeType(responseFormat); + break; + case "url": + result.data = response.data; + break; + default: + result.data = response.data; + } + + $.export( + "$summary", + `Successfully generated image from template ${templateId}`, + ); + return result; + } catch (error) { + const errorMessage = error.message || "Unknown error occurred"; + throw new Error(`Failed to generate image: ${errorMessage}`); + } + }, +}; diff --git a/components/orshot/actions/generate-image-studio-template/generate-image-studio-template.mjs b/components/orshot/actions/generate-image-studio-template/generate-image-studio-template.mjs new file mode 100644 index 0000000000000..25a6ed75d1e29 --- /dev/null +++ b/components/orshot/actions/generate-image-studio-template/generate-image-studio-template.mjs @@ -0,0 +1,139 @@ +import orshot from "../../orshot.app.mjs"; +import { + getMimeType, parseObject, +} from "../../common/utils.mjs"; + +export default { + key: "orshot-generate-image-studio-template", + name: "Generate Image from Studio Template", + description: "Generate an image from an Orshot Studio template using the Orshot API. [See the documentation](https://orshot.com/docs/api-reference/render-from-studio-template)", + version: "0.0.1", + type: "action", + props: { + orshot, + templateId: { + propDefinition: [ + orshot, + "studioTemplateId", + ], + }, + responseType: { + propDefinition: [ + orshot, + "responseType", + ], + }, + responseFormat: { + propDefinition: [ + orshot, + "responseFormat", + ], + }, + modifications: { + propDefinition: [ + orshot, + "modifications", + ], + optional: true, + }, + }, + async run({ $ }) { + const { + templateId, + responseType, + responseFormat, + modifications = {}, + } = this; + + // Input validation + if (!templateId) { + throw new Error("Template ID is required"); + } + + if (!responseType) { + throw new Error("Response type is required"); + } + + if (!responseFormat) { + throw new Error("Response format is required"); + } + + // Validate responseType + const validResponseTypes = [ + "base64", + "binary", + "url", + ]; + if (!validResponseTypes.includes(responseType)) { + throw new Error( + `Invalid response type. Must be one of: ${validResponseTypes.join( + ", ", + )}`, + ); + } + + // Validate responseFormat + const validFormats = [ + "png", + "jpg", + "jpeg", + "webp", + ]; + if (!validFormats.includes(responseFormat.toLowerCase())) { + throw new Error( + `Invalid response format. Must be one of: ${validFormats.join(", ")}`, + ); + } + + const validModifications = parseObject(modifications); + + try { + const response = await this.orshot.generateImageFromStudioTemplate({ + $, + data: { + templateId, + modifications: validModifications, + response: { + type: responseType, + format: responseFormat, + }, + }, + }); + + const result = { + templateId, + responseType, + responseFormat, + modifications: validModifications, + timestamp: new Date().toISOString(), + source: "orshot-pipedream", + }; + + // Handle different response types + switch (responseType) { + case "base64": + result.data = response.data; + result.mimeType = getMimeType(responseFormat); + break; + case "binary": + result.data = response; + result.mimeType = getMimeType(responseFormat); + break; + case "url": + result.data = response.data; + break; + default: + result.data = response.data; + } + + $.export( + "$summary", + `Successfully generated image from studio template ${templateId}`, + ); + return result; + } catch (error) { + const errorMessage = error.message || "Unknown error occurred"; + throw new Error(`Failed to generate image: ${errorMessage}`); + } + }, +}; diff --git a/components/orshot/actions/get-studio-template-modifications/get-studio-template-modifications.mjs b/components/orshot/actions/get-studio-template-modifications/get-studio-template-modifications.mjs new file mode 100644 index 0000000000000..e06487a8e8b52 --- /dev/null +++ b/components/orshot/actions/get-studio-template-modifications/get-studio-template-modifications.mjs @@ -0,0 +1,47 @@ +import orshot from "../../orshot.app.mjs"; + +export default { + key: "orshot-get-studio-template-modifications", + name: "Get Studio Template Modifications", + description: "Get available modification keys for a studio template", + version: "0.0.1", + type: "action", + props: { + orshot, + templateId: { + propDefinition: [ + orshot, + "studioTemplateId", + ], + }, + }, + async run({ $ }) { + const { templateId } = this; + + try { + const modifications = await this.orshot.getStudioTemplateModifications({ + $, + params: { + templateId, + }, + }); + + $.export( + "$summary", + `Successfully retrieved modifications for studio template ${templateId}`, + ); + + return { + templateId, + modifications, + count: modifications.length, + timestamp: new Date().toISOString(), + }; + } catch (error) { + const errorMessage = error.message || "Unknown error occurred"; + throw new Error( + `Failed to get studio template modifications: ${errorMessage}`, + ); + } + }, +}; diff --git a/components/orshot/actions/get-template-modifications/get-template-modifications.mjs b/components/orshot/actions/get-template-modifications/get-template-modifications.mjs new file mode 100644 index 0000000000000..307e5282f42d1 --- /dev/null +++ b/components/orshot/actions/get-template-modifications/get-template-modifications.mjs @@ -0,0 +1,46 @@ +import orshot from "../../orshot.app.mjs"; + +export default { + key: "orshot-get-template-modifications", + name: "Get Template Modifications", + description: "Get available modification keys for a library template", + version: "0.0.1", + type: "action", + props: { + orshot, + templateId: { + propDefinition: [ + orshot, + "templateId", + ], + description: "The ID of the template to get modifications for", + }, + }, + async run({ $ }) { + const { templateId } = this; + + try { + const modifications = await this.orshot.getTemplateModifications({ + $, + params: { + templateId, + }, + }); + + $.export( + "$summary", + `Successfully retrieved modifications for template ${templateId}`, + ); + + return { + templateId, + modifications, + count: modifications.length, + timestamp: new Date().toISOString(), + }; + } catch (error) { + const errorMessage = error.message || "Unknown error occurred"; + throw new Error(`Failed to get template modifications: ${errorMessage}`); + } + }, +}; diff --git a/components/orshot/actions/list-templates/list-templates.mjs b/components/orshot/actions/list-templates/list-templates.mjs new file mode 100644 index 0000000000000..8f742b9471dcd --- /dev/null +++ b/components/orshot/actions/list-templates/list-templates.mjs @@ -0,0 +1,33 @@ +import orshot from "../../orshot.app.mjs"; + +export default { + key: "orshot-list-templates", + name: "List Templates", + description: "Retrieve a list of available library templates from Orshot", + version: "0.0.1", + type: "action", + props: { + orshot, + }, + async run({ $ }) { + try { + const templates = await this.orshot.listTemplates({ + $, + }); + + $.export( + "$summary", + `Successfully retrieved ${templates.length} templates`, + ); + + return { + templates, + count: templates.length, + timestamp: new Date().toISOString(), + }; + } catch (error) { + const errorMessage = error.message || "Unknown error occurred"; + throw new Error(`Failed to list templates: ${errorMessage}`); + } + }, +}; diff --git a/components/orshot/common/utils.mjs b/components/orshot/common/utils.mjs new file mode 100644 index 0000000000000..81119626af8f3 --- /dev/null +++ b/components/orshot/common/utils.mjs @@ -0,0 +1,48 @@ +export const parseObject = (obj) => { + if (!obj) { + return {}; + } + if (typeof obj === "string") { + try { + return JSON.parse(obj); + } catch { + return obj; + } + } + if (Array.isArray(obj)) { + return obj.map(parseObject); + } + if (typeof obj === "object") { + return Object.fromEntries( + Object.entries(obj).map(([ + key, + value, + ]) => [ + key, + parseObject(value), + ]), + ); + } + return obj; +}; + +/** + * Get the MIME type for a given file format + * @param {string} format - The file format (e.g., 'png', 'jpg') + * @returns {string} The corresponding MIME type +*/ +export const getMimeType = (format) => { + if (!format || typeof format !== "string") { + return "application/octet-stream"; + } + + const mimeTypes = { + png: "image/png", + jpg: "image/jpeg", + jpeg: "image/jpeg", + webp: "image/webp", + }; + + const normalizedFormat = format.toLowerCase().trim(); + return mimeTypes[normalizedFormat] || "application/octet-stream"; +}; diff --git a/components/orshot/orshot.app.mjs b/components/orshot/orshot.app.mjs index 661f720f22e9a..8366218aa0164 100644 --- a/components/orshot/orshot.app.mjs +++ b/components/orshot/orshot.app.mjs @@ -1,11 +1,124 @@ +import { axios } from "@pipedream/platform"; + export default { type: "app", app: "orshot", - propDefinitions: {}, + propDefinitions: { + templateId: { + type: "string", + label: "Template ID", + description: "The ID of the template to render", + async options() { + const templates = await this.listTemplates(); + return templates.map((template) => ({ + label: template.title, + value: template.id, + })); + }, + }, + studioTemplateId: { + type: "string", + label: "Studio Template ID", + description: "The ID of the studio template to render. You can find this on the template playground page.", + }, + responseType: { + type: "string", + label: "Response Type", + description: "Type of response to return", + options: [ + { + label: "Base64", + value: "base64", + }, + { + label: "Binary", + value: "binary", + }, + { + label: "URL", + value: "url", + }, + ], + default: "base64", + }, + responseFormat: { + type: "string", + label: "Response Format", + description: "Format of the rendered image", + options: [ + { + label: "PNG", + value: "png", + }, + { + label: "JPG", + value: "jpg", + }, + { + label: "JPEG", + value: "jpeg", + }, + { + label: "WebP", + value: "webp", + }, + ], + default: "png", + }, + modifications: { + type: "object", + label: "Template Modifications", + description: "Key-value pairs for template modifications. The keys should match the modification keys available for your template.", + }, + }, methods: { - // this.$auth contains connected account data - authKeys() { - console.log(Object.keys(this.$auth)); + _baseUrl() { + return "https://api.orshot.com/v1"; + }, + _makeRequest({ + $ = this, path, headers, ...otherOpts + }) { + return axios($, { + ...otherOpts, + url: `${this._baseUrl()}${path}`, + headers: { + ...headers, + "Authorization": `Bearer ${this.$auth.token}`, + "Content-Type": "application/json", + }, + }); + }, + listTemplates(opts = {}) { + return this._makeRequest({ + path: "/templates", + ...opts, + }); + }, + getTemplateModifications(opts = {}) { + return this._makeRequest({ + path: "/templates/modifications", + ...opts, + }); + }, + getStudioTemplateModifications(opts = {}) { + return this._makeRequest({ + path: "/studio/template/modifications", + ...opts, + }); + }, + generateImageFromLibraryTemplate(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/generate/images", + ...opts, + }); + }, + generateImageFromStudioTemplate(opts = {}) { + return this._makeRequest({ + method: "POST", + path: "/studio/render", + ...opts, + }); }, }, -}; \ No newline at end of file +}; diff --git a/components/orshot/package.json b/components/orshot/package.json index 8bd1ffcc6905e..4e2a6b0c983d9 100644 --- a/components/orshot/package.json +++ b/components/orshot/package.json @@ -1,6 +1,6 @@ { "name": "@pipedream/orshot", - "version": "0.0.1", + "version": "0.1.0", "description": "Pipedream Orshot Components", "main": "orshot.app.mjs", "keywords": [ @@ -11,5 +11,8 @@ "author": "Pipedream (https://pipedream.com/)", "publishConfig": { "access": "public" + }, + "dependencies": { + "@pipedream/platform": "^3.1.0" } -} \ No newline at end of file +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ddcd0dec12bb..0322f7747e5c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2147,8 +2147,7 @@ importers: components/captaindata: {} - components/capturekit: - specifiers: {} + components/capturekit: {} components/carbone: {} @@ -4406,8 +4405,7 @@ importers: specifier: ^1.4.1 version: 1.6.6 - components/exact_mails: - specifiers: {} + components/exact_mails: {} components/exhibitday: dependencies: @@ -9558,7 +9556,10 @@ importers: version: 1.6.6 components/orshot: - specifiers: {} + dependencies: + '@pipedream/platform': + specifier: ^3.1.0 + version: 3.1.0 components/ortto: dependencies: @@ -14488,8 +14489,7 @@ importers: components/veriff: {} - components/verifi_email: - specifiers: {} + components/verifi_email: {} components/verifiedemail: {} @@ -36168,7 +36168,7 @@ snapshots: '@pipedream/ramp@0.1.2': dependencies: - '@pipedream/platform': 3.0.3 + '@pipedream/platform': 3.1.0 uuid: 10.0.0 transitivePeerDependencies: - debug @@ -36212,7 +36212,7 @@ snapshots: '@pipedream/shopify@0.7.0': dependencies: - '@pipedream/platform': 3.0.3 + '@pipedream/platform': 3.1.0 async-retry: 1.3.3 bottleneck: 2.19.5 form-data: 4.0.2