Add Activepieces integration for workflow automation

- Add Activepieces fork with SmoothSchedule custom piece
- Create integrations app with Activepieces service layer
- Add embed token endpoint for iframe integration
- Create Automations page with embedded workflow builder
- Add sidebar visibility fix for embed mode
- Add list inactive customers endpoint to Public API
- Include SmoothSchedule triggers: event created/updated/cancelled
- Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-18 22:59:37 -05:00
parent 9848268d34
commit 3aa7199503
16292 changed files with 1284892 additions and 4708 deletions

View File

@@ -0,0 +1,33 @@
{
"extends": [
"../../../../.eslintrc.base.json"
],
"ignorePatterns": [
"!**/*"
],
"overrides": [
{
"files": [
"*.ts",
"*.tsx",
"*.js",
"*.jsx"
],
"rules": {}
},
{
"files": [
"*.ts",
"*.tsx"
],
"rules": {}
},
{
"files": [
"*.js",
"*.jsx"
],
"rules": {}
}
]
}

View File

@@ -0,0 +1,7 @@
# pieces-promptmate
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-promptmate` to build the library.

View File

@@ -0,0 +1,10 @@
{
"name": "@activepieces/piece-promptmate",
"version": "0.0.1",
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"dependencies": {
"tslib": "^2.3.0"
}
}

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-promptmate",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/promptmate/src",
"projectType": "library",
"release": {
"version": {
"manifestRootsToUpdate": [
"dist/{projectRoot}"
],
"currentVersionResolver": "git-tag",
"fallbackCurrentVersionResolver": "disk"
}
},
"tags": [],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/packages/pieces/community/promptmate",
"tsConfig": "packages/pieces/community/promptmate/tsconfig.lib.json",
"packageJson": "packages/pieces/community/promptmate/package.json",
"main": "packages/pieces/community/promptmate/src/index.ts",
"assets": [
"packages/pieces/community/promptmate/*.md",
{
"input": "packages/pieces/community/promptmate/src/i18n",
"output": "./src/i18n",
"glob": "**/!(i18n.json)"
}
],
"buildableProjectDepsInPackageJsonType": "dependencies",
"updateBuildableProjectDepsInPackageJson": true
},
"dependsOn": [
"prebuild",
"^build"
]
},
"nx-release-publish": {
"options": {
"packageRoot": "dist/{projectRoot}"
}
},
"prebuild": {
"dependsOn": [
"^build"
],
"executor": "nx:run-commands",
"options": {
"cwd": "packages/pieces/community/promptmate",
"command": "bun install --no-save --silent"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
}
}
}

View File

@@ -0,0 +1,68 @@
{
"AI-powered automation platform": "AI-powered automation platform",
"Your PromptMate API key": "Your PromptMate API key",
"List Apps": "List Apps",
"Run PromptMate App": "Run PromptMate App",
"Get Job Status and Result": "Get Job Status and Result",
"Get App Details": "Get App Details",
"Get Last Result Rows": "Get Last Result Rows",
"Use Template": "Use Template",
"Get User Information": "Get User Information",
"List Projects": "List Projects",
"Custom API Call": "Custom API Call",
"Retrieve a list of available apps": "Retrieve a list of available apps",
"Runs a PromptMate app with the specified data": "Runs a PromptMate app with the specified data",
"Retrieve the status and results of a PromptMate app job": "Retrieve the status and results of a PromptMate app job",
"Retrieve detailed information about a specific PromptMate app": "Retrieve detailed information about a specific PromptMate app",
"Retrieve the last result rows of a PromptMate app for examples or testing": "Retrieve the last result rows of a PromptMate app for examples or testing",
"Create an app from a specific PromptMate template": "Create an app from a specific PromptMate template",
"Retrieve user information associated with the API key": "Retrieve user information associated with the API key",
"Retrieve a list of available PromptMate projects": "Retrieve a list of available PromptMate projects",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"App": "App",
"Data": "Data",
"Callback URL": "Callback URL",
"Disable Email Notification": "Disable Email Notification",
"Configuration": "Configuration",
"Job ID": "Job ID",
"Only Default Result Fields": "Only Default Result Fields",
"Limit": "Limit",
"Template ID": "Template ID",
"Method": "Method",
"Headers": "Headers",
"Query Parameters": "Query Parameters",
"Body": "Body",
"Response is Binary ?": "Response is Binary ?",
"No Error on Failure": "No Error on Failure",
"Timeout (in seconds)": "Timeout (in seconds)",
"Select the PromptMate app to run": "Select the PromptMate app to run",
"Array of data objects to process. Each object must contain the required data fields for the selected app.": "Array of data objects to process. Each object must contain the required data fields for the selected app.",
"URL to which the result of the job will be sent (optional)": "URL to which the result of the job will be sent (optional)",
"Send an email to the user when the job has finished": "Send an email to the user when the job has finished",
"Configuration settings for the job (language, country, etc.)": "Configuration settings for the job (language, country, etc.)",
"Select the app for which to get job status": "Select the app for which to get job status",
"The ID of the job to check": "The ID of the job to check",
"Return only the default result fields": "Return only the default result fields",
"Select the app to get details for": "Select the app to get details for",
"Select the app to get last results for": "Select the app to get last results for",
"Maximum number of result rows to return": "Maximum number of result rows to return",
"The ID of the template to use": "The ID of the template to use",
"Authorization headers are injected automatically from your connection.": "Authorization headers are injected automatically from your connection.",
"Enable for files like PDFs, images, etc..": "Enable for files like PDFs, images, etc..",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"New App Result": "New App Result",
"Triggers when there is a new app result from PromptMate": "Triggers when there is a new app result from PromptMate",
"Restrict to Apps": "Restrict to Apps",
"Trigger Level": "Trigger Level",
"Webhook Reference": "Webhook Reference",
"Only trigger for results from these specific apps. Leave empty to trigger for all apps.": "Only trigger for results from these specific apps. Leave empty to trigger for all apps.",
"Choose when to trigger the webhook": "Choose when to trigger the webhook",
"Optional reference for this webhook (used for identification)": "Optional reference for this webhook (used for identification)",
"Row Level": "Row Level",
"Job Level": "Job Level"
}

View File

@@ -0,0 +1,72 @@
import {
AuthenticationType,
createCustomApiCallAction,
httpClient,
HttpMethod,
} from '@activepieces/pieces-common';
import { PieceAuth, createPiece } from "@activepieces/pieces-framework";
import { PieceCategory } from '@activepieces/shared';
import { listApps } from './lib/actions/list-apps';
import { runApp } from './lib/actions/run-app';
import { getJobStatus } from './lib/actions/get-job-status';
import { getAppDetails } from './lib/actions/get-app-details';
import { getLastResults } from './lib/actions/get-last-results';
import { useTemplate } from './lib/actions/use-template';
import { getUserInfo } from './lib/actions/get-user-info';
import { listProjects } from './lib/actions/list-projects';
import { newAppResult } from './lib/triggers/new-app-result';
export const promptmateAuth = PieceAuth.SecretText({
displayName: 'API Key',
description: 'Your PromptMate API key',
required: true,
validate: async (auth) => {
try {
await httpClient.sendRequest({
url: 'https://api.promptmate.io/v1/apps',
method: HttpMethod.GET,
headers: {
'x-api-key': auth.auth as string,
},
});
return {
valid: true,
};
} catch (e) {
return {
valid: false,
error: 'Invalid API key',
};
}
},
});
export const promptmate = createPiece({
displayName: "PromptMate",
description: "AI-powered automation platform",
auth: promptmateAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: "https://cdn.activepieces.com/pieces/promptmate.png",
categories: [PieceCategory.ARTIFICIAL_INTELLIGENCE],
authors: ["onyedikachi-david"],
actions: [
listApps,
runApp,
getJobStatus,
getAppDetails,
getLastResults,
useTemplate,
getUserInfo,
listProjects,
createCustomApiCallAction({
baseUrl: () => 'https://api.promptmate.io/v1',
auth: promptmateAuth,
authMapping: async (auth) => ({
'x-api-key': auth.secret_text,
}),
}),
],
triggers: [newAppResult],
});

View File

@@ -0,0 +1,45 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { getAppDropdownOptions } from '../common';
export const getAppDetails = createAction({
auth: promptmateAuth,
name: 'get_app_details',
displayName: 'Get App Details',
description: 'Retrieve detailed information about a specific PromptMate app',
props: {
appId: Property.Dropdown({
displayName: 'App',
description: 'Select the app to get details for',
required: true,
refreshers: [],
auth: promptmateAuth,
options: async ({ auth }) => {
if (!auth) {
return {
options: [],
disabled: true,
};
}
return await getAppDropdownOptions(auth.secret_text);
},
}),
},
async run({ auth, propsValue }) {
const { appId } = propsValue;
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: 'https://api.promptmate.io/v1/app',
headers: {
'x-api-key': auth.secret_text,
},
queryParams: {
appId,
},
});
return response.body;
},
});

View File

@@ -0,0 +1,63 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { getAppDropdownOptions } from '../common';
export const getJobStatus = createAction({
auth: promptmateAuth,
name: 'get_job_status',
displayName: 'Get Job Status and Result',
description: 'Retrieve the status and results of a PromptMate app job',
props: {
appId: Property.Dropdown({
displayName: 'App',
description: 'Select the app for which to get job status',
required: true,
refreshers: [],
auth: promptmateAuth,
options: async ({ auth }) => {
if (!auth) {
return {
options: [],
disabled: true,
};
}
return await getAppDropdownOptions(auth.secret_text);
},
}),
jobId: Property.ShortText({
displayName: 'Job ID',
description: 'The ID of the job to check',
required: true,
}),
onlyDefaultResultFields: Property.Checkbox({
displayName: 'Only Default Result Fields',
description: 'Return only the default result fields',
required: false,
defaultValue: true,
}),
},
async run({ auth, propsValue }) {
const { appId, jobId, onlyDefaultResultFields } = propsValue;
const queryParams: Record<string, string> = {
appId,
jobId,
};
if (onlyDefaultResultFields !== undefined) {
queryParams['onlyDefaultResultFields'] = onlyDefaultResultFields.toString();
}
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: 'https://api.promptmate.io/v1/app-jobs',
headers: {
'x-api-key': auth.secret_text,
},
queryParams,
});
return response.body;
},
});

View File

@@ -0,0 +1,67 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { getAppDropdownOptions } from '../common';
export const getLastResults = createAction({
auth: promptmateAuth,
name: 'get_last_results',
displayName: 'Get Last Result Rows',
description: 'Retrieve the last result rows of a PromptMate app for examples or testing',
props: {
appId: Property.Dropdown({
displayName: 'App',
description: 'Select the app to get last results for',
required: true,
refreshers: [],
auth: promptmateAuth,
options: async ({ auth }) => {
if (!auth) {
return {
options: [],
disabled: true,
};
}
return await getAppDropdownOptions(auth.secret_text);
},
}),
onlyDefaultResultFields: Property.Checkbox({
displayName: 'Only Default Result Fields',
description: 'Return only the default result fields',
required: false,
defaultValue: true,
}),
limit: Property.Number({
displayName: 'Limit',
description: 'Maximum number of result rows to return',
required: false,
defaultValue: 20,
}),
},
async run({ auth, propsValue }) {
const { appId, onlyDefaultResultFields, limit } = propsValue;
const queryParams: Record<string, string> = {
appId,
};
if (onlyDefaultResultFields !== undefined) {
queryParams['onlyDefaultResultFields'] = onlyDefaultResultFields.toString();
}
if (limit !== undefined) {
queryParams['limit'] = limit.toString();
}
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: 'https://api.promptmate.io/v1/app-results',
headers: {
'x-api-key': auth.secret_text,
},
queryParams,
});
return response.body;
},
});

View File

@@ -0,0 +1,22 @@
import { createAction } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
export const getUserInfo = createAction({
auth: promptmateAuth,
name: 'get_user_info',
displayName: 'Get User Information',
description: 'Retrieve user information associated with the API key',
props: {},
async run({ auth }) {
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: 'https://api.promptmate.io/v1/userInfo',
headers: {
'x-api-key': auth.secret_text,
},
});
return response.body;
},
});

View File

@@ -0,0 +1,27 @@
import { createAction } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
export const listApps = createAction({
auth: promptmateAuth,
name: 'list_apps',
displayName: 'List Apps',
description: 'Retrieve a list of available apps',
props: {},
async run({ auth }) {
const response = await httpClient.sendRequest<{
appId: string;
appName: string;
creditEstimate: number;
dataFields: string[];
}[]>({
method: HttpMethod.GET,
url: 'https://api.promptmate.io/v1/apps',
headers: {
'x-api-key': auth.secret_text,
},
});
return response.body;
},
});

View File

@@ -0,0 +1,22 @@
import { createAction } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
export const listProjects = createAction({
auth: promptmateAuth,
name: 'list_projects',
displayName: 'List Projects',
description: 'Retrieve a list of available PromptMate projects',
props: {},
async run({ auth }) {
const response = await httpClient.sendRequest({
method: HttpMethod.GET,
url: 'https://api.promptmate.io/v1/projects',
headers: {
'x-api-key': auth.secret_text,
},
});
return response.body;
},
});

View File

@@ -0,0 +1,82 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { getAppDropdownOptions } from '../common';
export const runApp = createAction({
auth: promptmateAuth,
name: 'run_app',
displayName: 'Run PromptMate App',
description: 'Runs a PromptMate app with the specified data',
props: {
appId: Property.Dropdown({
auth: promptmateAuth,
displayName: 'App',
description: 'Select the PromptMate app to run',
required: true,
refreshers: [],
options: async ({ auth }) => {
if (!auth) {
return {
options: [],
disabled: true,
};
}
return await getAppDropdownOptions(auth.secret_text);
},
}),
data: Property.Array({
displayName: 'Data',
description: 'Array of data objects to process. Each object must contain the required data fields for the selected app.',
required: true,
}),
callBackUrl: Property.ShortText({
displayName: 'Callback URL',
description: 'URL to which the result of the job will be sent (optional)',
required: false,
}),
noMailOnFinish: Property.Checkbox({
displayName: 'Disable Email Notification',
description: 'Send an email to the user when the job has finished',
required: false,
defaultValue: true,
}),
config: Property.Object({
displayName: 'Configuration',
description: 'Configuration settings for the job (language, country, etc.)',
required: false,
}),
},
async run({ auth, propsValue }) {
const { appId, data, callBackUrl, noMailOnFinish, config } = propsValue;
const requestBody: any = {
appId,
data,
};
if (callBackUrl) {
requestBody.callBackUrl = callBackUrl;
}
if (noMailOnFinish !== undefined) {
requestBody.noMailOnFinish = noMailOnFinish;
}
if (config) {
requestBody.config = config;
}
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: 'https://api.promptmate.io/v1/app-jobs',
headers: {
'x-api-key': auth.secret_text,
'Content-Type': 'application/json',
},
body: requestBody,
});
return response.body;
},
});

View File

@@ -0,0 +1,34 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
export const useTemplate = createAction({
auth: promptmateAuth,
name: 'use_template',
displayName: 'Use Template',
description: 'Create an app from a specific PromptMate template',
props: {
templateId: Property.ShortText({
displayName: 'Template ID',
description: 'The ID of the template to use',
required: true,
}),
},
async run({ auth, propsValue }) {
const { templateId } = propsValue;
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: 'https://api.promptmate.io/v1/templates/use',
headers: {
'x-api-key': auth.secret_text,
'Content-Type': 'application/json',
},
body: {
templateId,
},
});
return response.body;
},
});

View File

@@ -0,0 +1,47 @@
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
export interface PromptMateApp {
appId: string;
appName: string;
creditEstimate: number;
dataFields: string[];
}
export const getApps = async (auth: string): Promise<PromptMateApp[]> => {
const response = await httpClient.sendRequest<PromptMateApp[]>({
method: HttpMethod.GET,
url: 'https://api.promptmate.io/v1/apps',
headers: {
'x-api-key': auth,
},
});
return response.body;
};
export const getAppDropdownOptions = async (auth: string) => {
if (!auth) {
return {
disabled: true,
placeholder: 'Enter your API key first',
options: [],
};
}
try {
const apps = await getApps(auth);
return {
disabled: false,
options: apps.map((app) => ({
label: app.appName,
value: app.appId,
})),
};
} catch (error) {
return {
disabled: true,
options: [],
placeholder: "Couldn't load apps, API key is invalid",
};
}
};

View File

@@ -0,0 +1,133 @@
import { createTrigger, TriggerStrategy, Property } from '@activepieces/pieces-framework';
import { promptmateAuth } from '../..';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { getAppDropdownOptions } from '../common';
interface WebhookInfo {
webhookId: string;
webhookReference: string;
}
export const newAppResult = createTrigger({
auth: promptmateAuth,
name: 'new_app_result',
displayName: 'New App Result',
description: 'Triggers when there is a new app result from PromptMate',
props: {
restrictedAppIds: Property.MultiSelectDropdown({
displayName: 'Restrict to Apps',
description: 'Only trigger for results from these specific apps. Leave empty to trigger for all apps.',
required: false,
refreshers: [],
auth: promptmateAuth,
options: async ({ auth }) => {
if (!auth) {
return {
options: [],
disabled: true,
};
}
const options = await getAppDropdownOptions(auth.secret_text);
return {
...options,
options: options.options || [],
};
},
}),
webhookType: Property.StaticDropdown({
displayName: 'Trigger Level',
description: 'Choose when to trigger the webhook',
required: true,
defaultValue: 'row',
options: {
options: [
{
label: 'Row Level',
value: 'row',
},
{
label: 'Job Level',
value: 'job',
},
],
},
}),
webhookReference: Property.ShortText({
displayName: 'Webhook Reference',
description: 'Optional reference for this webhook (used for identification)',
required: false,
}),
},
sampleData: {
jobId: 'job_123456',
jobStatus: 'completed',
results: [
{
input: { field1: 'value1', field2: 'value2' },
output: { result: 'processed data' },
status: 'success',
},
],
},
type: TriggerStrategy.WEBHOOK,
async onEnable(context) {
const { restrictedAppIds, webhookType, webhookReference } = context.propsValue;
const webhookName = `ActivePieces-${webhookReference || `webhook-${Date.now()}`}`;
const requestBody: any = {
webhookName,
webhookType,
endpointUrl: context.webhookUrl,
};
if (webhookReference) {
requestBody.webhookReference = webhookReference;
}
if (restrictedAppIds && restrictedAppIds.length > 0) {
requestBody.restrictedAppIds = restrictedAppIds;
}
const response = await httpClient.sendRequest<WebhookInfo[]>({
method: HttpMethod.POST,
url: 'https://api.promptmate.io/v1/webhooks',
headers: {
'x-api-key': context.auth.secret_text,
'Content-Type': 'application/json',
},
body: requestBody,
});
const webhook = response.body[0];
if (!webhook) {
throw new Error('Failed to create webhook');
}
await context.store.put<WebhookInfo>('promptmate_webhook', {
webhookId: webhook.webhookId,
webhookReference: webhookReference || webhookName,
});
},
async onDisable(context) {
const webhookInfo = await context.store.get<WebhookInfo>('promptmate_webhook');
if (webhookInfo) {
await httpClient.sendRequest({
method: HttpMethod.DELETE,
url: 'https://api.promptmate.io/v1/webhooks',
headers: {
'x-api-key': context.auth.secret_text,
'Content-Type': 'application/json',
},
body: {
webhookId: webhookInfo.webhookId,
},
});
}
},
async run(context) {
const payload = context.payload.body as any;
return [payload];
},
});

View File

@@ -0,0 +1,20 @@
{
"extends": "../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"importHelpers": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
}
]
}

View File

@@ -0,0 +1,9 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"include": ["src/**/*.ts"]
}