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-rabbitmq
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build pieces-rabbitmq` to build the library.

View File

@@ -0,0 +1,10 @@
{
"name": "@activepieces/piece-rabbitmq",
"version": "0.0.8",
"dependencies": {
"amqplib": "0.10.7"
},
"devDependencies": {
"@types/amqplib": "0.10.7"
}
}

View File

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

View File

@@ -0,0 +1,24 @@
{
"Host": "Host",
"Username": "Benutzername",
"Password": "Kennwort",
"Port": "Port",
"Virtual Host": "Virtueller Host",
"Rabbitmq Auth": "Rabbitmq Auth",
"sendMessageToExchange": "sendMessageToExchange",
"sendMessageToQueue": "sendMessageToQueue",
"Send a message on a RabbitMQ exchange": "Senden Sie eine Nachricht bei einem RabbitMQ-Austausch",
"Send a message on a RabbitMQ queue": "Eine Nachricht an eine RabbitMQ Warteschlange senden",
"Exchange": "Umtausch",
"Routing Key (Optional)": "Routing-Taste (optional)",
"Data": "Daten",
"Queue": "Warteschlange",
"The name of the exchange to send the message to": "Der Name des Austauschs, an den die Nachricht gesendet werden soll",
"The routing key to use when sending the message": "Der Routing-Schlüssel zum Senden der Nachricht",
"The data to send": "Die zu sendenden Daten",
"Message Received": "Nachricht empfangen",
"Triggers when a message is received on a RabbitMQ queue": "Wird ausgelöst, wenn eine Nachricht in einer RabbitMQ Warteschlange empfangen wird",
"Max Messages Per Poll": "Max. Nachrichten pro Umfrage",
"The name of the queue to listen to": "Der Name der Warteschlange",
"The maximum number of messages to fetch per poll": "Maximale Anzahl von Nachrichten pro Umfrage"
}

View File

@@ -0,0 +1,24 @@
{
"Host": "Anfitrión",
"Username": "Usuario",
"Password": "Contraseña",
"Port": "Puerto",
"Virtual Host": "Servidor virtual",
"Rabbitmq Auth": "Autorización Rabbitmq",
"sendMessageToExchange": "enviar mensaje a intercambio",
"sendMessageToQueue": "enviar mensaje a cola",
"Send a message on a RabbitMQ exchange": "Enviar un mensaje en un intercambio de RabbitMQ",
"Send a message on a RabbitMQ queue": "Enviar un mensaje a una cola de RabbitMQ",
"Exchange": "Intercambio",
"Routing Key (Optional)": "Clave de ruta (opcional)",
"Data": "Datos",
"Queue": "Cola",
"The name of the exchange to send the message to": "El nombre del intercambio al que enviar el mensaje",
"The routing key to use when sending the message": "La clave de enrutamiento a usar al enviar el mensaje",
"The data to send": "Los datos a enviar",
"Message Received": "Mensaje recibido",
"Triggers when a message is received on a RabbitMQ queue": "Dispara cuando un mensaje es recibido en una cola de RabbitMQ",
"Max Messages Per Poll": "Máximo de mensajes por encuesta",
"The name of the queue to listen to": "El nombre de la cola a la que escuchar",
"The maximum number of messages to fetch per poll": "El número máximo de mensajes a buscar por encuesta"
}

View File

@@ -0,0 +1,24 @@
{
"Host": "Hôte",
"Username": "Nom d'utilisateur",
"Password": "Password",
"Port": "Port",
"Virtual Host": "Hôte virtuel",
"Rabbitmq Auth": "Auth lapbitmq",
"sendMessageToExchange": "Envoyer un message à échanger",
"sendMessageToQueue": "Envoyer un message à la file d'attente",
"Send a message on a RabbitMQ exchange": "Envoyer un message sur un échange Lapin MQ",
"Send a message on a RabbitMQ queue": "Envoyer un message sur une file d'attente de Lapin MQ",
"Exchange": "Échanger",
"Routing Key (Optional)": "Clé de routage (facultatif)",
"Data": "Donnée",
"Queue": "File d'attente",
"The name of the exchange to send the message to": "Le nom de l'échange à qui envoyer le message à",
"The routing key to use when sending the message": "La clé de routage à utiliser lors de l'envoi du message",
"The data to send": "Les données à envoyer",
"Message Received": "Message reçu",
"Triggers when a message is received on a RabbitMQ queue": "Déclenche lorsqu'un message est reçu dans une file d'attente de Lapin MQ",
"Max Messages Per Poll": "Nombre maximum de messages par sondage",
"The name of the queue to listen to": "Le nom de la file d'attente à écouter",
"The maximum number of messages to fetch per poll": "Le nombre maximum de messages à récupérer par sondage"
}

View File

@@ -0,0 +1,24 @@
{
"Host": "ホスト",
"Username": "ユーザー名",
"Password": "Password",
"Port": "ポート",
"Virtual Host": "バーチャルホスト",
"Rabbitmq Auth": "Rabbitmq 認証",
"sendMessageToExchange": "sendMessageToExchange",
"sendMessageToQueue": "sendMessageToQueue",
"Send a message on a RabbitMQ exchange": "RabbitMQ 取引所にメッセージを送信",
"Send a message on a RabbitMQ queue": "RabbitMQキューにメッセージを送信する",
"Exchange": "交換",
"Routing Key (Optional)": "ルーティングキー (任意)",
"Data": "データ",
"Queue": "キュー",
"The name of the exchange to send the message to": "メッセージを送信する取引所の名前",
"The routing key to use when sending the message": "メッセージを送信するときに使用するルーティングキー",
"The data to send": "送信するデータ",
"Message Received": "受信したメッセージ",
"Triggers when a message is received on a RabbitMQ queue": "RabbitMQキューでメッセージが受信されたときにトリガーします",
"Max Messages Per Poll": "アンケート毎の最大メッセージ",
"The name of the queue to listen to": "リッスンするキューの名前",
"The maximum number of messages to fetch per poll": "The maximum number of messages to fetch per poll"
}

View File

@@ -0,0 +1,24 @@
{
"Host": "Hostnaam",
"Username": "Gebruikersnaam",
"Password": "Wachtwoord",
"Port": "Poort",
"Virtual Host": "Virtuele host",
"Rabbitmq Auth": "Rabbitmq Auth",
"sendMessageToExchange": "sendMessageToExchange",
"sendMessageToQueue": "sendMessageWachtrij",
"Send a message on a RabbitMQ exchange": "Stuur een bericht op een RabbitMQ uitwisseling",
"Send a message on a RabbitMQ queue": "Stuur een bericht op een RabbitMQ wachtrij",
"Exchange": "Ruil",
"Routing Key (Optional)": "Routesleutel (optioneel)",
"Data": "Gegevens",
"Queue": "Wachtrij",
"The name of the exchange to send the message to": "De naam van het beurs om het bericht naar te sturen",
"The routing key to use when sending the message": "De te gebruiken routing sleutel bij het verzenden van het bericht",
"The data to send": "De gegevens om te verzenden",
"Message Received": "Bericht ontvangen",
"Triggers when a message is received on a RabbitMQ queue": "Triggert wanneer een bericht wordt ontvangen op een RabbitMQ wachtrij",
"Max Messages Per Poll": "Maximaal aantal berichten per poll",
"The name of the queue to listen to": "De naam van de wachtrij om naar te luisteren",
"The maximum number of messages to fetch per poll": "Het maximum aantal berichten om op te halen per poll"
}

View File

@@ -0,0 +1,24 @@
{
"Host": "Servidor",
"Username": "Usuário:",
"Password": "Senha",
"Port": "Porta",
"Virtual Host": "Host Virtual",
"Rabbitmq Auth": "Autenticação de Rabbitmq",
"sendMessageToExchange": "EnviarMensagemPara-Troca",
"sendMessageToQueue": "EnviaMensagemPara/Fila",
"Send a message on a RabbitMQ exchange": "Enviar uma mensagem em um câmbio RabbitMQ",
"Send a message on a RabbitMQ queue": "Enviar uma mensagem em uma fila de RabbitMQ",
"Exchange": "Câmbio",
"Routing Key (Optional)": "Chave de roteamento (opcional)",
"Data": "Dado",
"Queue": "Fila",
"The name of the exchange to send the message to": "O nome do câmbio para enviar a mensagem para",
"The routing key to use when sending the message": "A chave de roteamento a ser usada ao enviar a mensagem",
"The data to send": "Os dados a enviar",
"Message Received": "Mensagem Recebida",
"Triggers when a message is received on a RabbitMQ queue": "Aciona quando uma mensagem é recebida em uma fila de RabbitMQ",
"Max Messages Per Poll": "Máximo de Mensagens Por Enquete",
"The name of the queue to listen to": "O nome da fila para ouvir",
"The maximum number of messages to fetch per poll": "O número máximo de mensagens para buscar por enquete"
}

View File

@@ -0,0 +1,25 @@
{
"RabbitMQ": "RabbitMQ",
"Host": "Хост",
"Username": "Имя пользователя",
"Password": "Пароль",
"Port": "Порт",
"Virtual Host": "Виртуальный хост",
"Rabbitmq Auth": "Rabbitmq Аутент",
"sendMessageToExchange": "sendMessageToExchange",
"sendMessageToQueue": "отправить сообщение в очередь",
"Send a message on a RabbitMQ exchange": "Отправить сообщение на обмене RabbitMQ",
"Send a message on a RabbitMQ queue": "Отправить сообщение в очереди RabbitMQ",
"Exchange": "Обмен",
"Routing Key (Optional)": "Ключ маршрутизации (необязательно)",
"Data": "Данные",
"Queue": "Очередь",
"The name of the exchange to send the message to": "Название обмена для отправки сообщения",
"The routing key to use when sending the message": "Ключ маршрутизации, используемый при отправке сообщения",
"The data to send": "Данные для отправки",
"Message Received": "Сообщение получено",
"Triggers when a message is received on a RabbitMQ queue": "Включает при получении сообщения в очереди RabbitMQ",
"Max Messages Per Poll": "Максимум сообщений на опрос",
"The name of the queue to listen to": "Название очереди для служения",
"The maximum number of messages to fetch per poll": "Максимальное количество сообщений на опрос"
}

View File

@@ -0,0 +1,24 @@
{
"Host": "Host",
"Username": "Username",
"Password": "Password",
"Port": "Port",
"Virtual Host": "Virtual Host",
"Rabbitmq Auth": "Rabbitmq Auth",
"sendMessageToExchange": "sendMessageToExchange",
"sendMessageToQueue": "sendMessageToQueue",
"Send a message on a RabbitMQ exchange": "Send a message on a RabbitMQ exchange",
"Send a message on a RabbitMQ queue": "Send a message on a RabbitMQ queue",
"Exchange": "Exchange",
"Routing Key (Optional)": "Routing Key (Optional)",
"Data": "Data",
"Queue": "Queue",
"The name of the exchange to send the message to": "The name of the exchange to send the message to",
"The routing key to use when sending the message": "The routing key to use when sending the message",
"The data to send": "The data to send",
"Message Received": "Message Received",
"Triggers when a message is received on a RabbitMQ queue": "Triggers when a message is received on a RabbitMQ queue",
"Max Messages Per Poll": "Max Messages Per Poll",
"The name of the queue to listen to": "The name of the queue to listen to",
"The maximum number of messages to fetch per poll": "The maximum number of messages to fetch per poll"
}

View File

@@ -0,0 +1,25 @@
{
"RabbitMQ": "RabbitMQ",
"Host": "Host",
"Username": "Username",
"Password": "Password",
"Port": "Port",
"Virtual Host": "Virtual Host",
"Rabbitmq Auth": "Rabbitmq Auth",
"sendMessageToExchange": "sendMessageToExchange",
"sendMessageToQueue": "sendMessageToQueue",
"Send a message on a RabbitMQ exchange": "Send a message on a RabbitMQ exchange",
"Send a message on a RabbitMQ queue": "Send a message on a RabbitMQ queue",
"Exchange": "Exchange",
"Routing Key (Optional)": "Routing Key (Optional)",
"Data": "Data",
"Queue": "Queue",
"The name of the exchange to send the message to": "The name of the exchange to send the message to",
"The routing key to use when sending the message": "The routing key to use when sending the message",
"The data to send": "The data to send",
"Message Received": "Message Received",
"Triggers when a message is received on a RabbitMQ queue": "Triggers when a message is received on a RabbitMQ queue",
"Max Messages Per Poll": "Max Messages Per Poll",
"The name of the queue to listen to": "The name of the queue to listen to",
"The maximum number of messages to fetch per poll": "The maximum number of messages to fetch per poll"
}

View File

@@ -0,0 +1,24 @@
{
"Host": "主机",
"Username": "用户名",
"Password": "密码",
"Port": "端口",
"Virtual Host": "Virtual Host",
"Rabbitmq Auth": "Rabbitmq Auth",
"sendMessageToExchange": "sendMessageToExchange",
"sendMessageToQueue": "sendMessageToQueue",
"Send a message on a RabbitMQ exchange": "Send a message on a RabbitMQ exchange",
"Send a message on a RabbitMQ queue": "Send a message on a RabbitMQ queue",
"Exchange": "Exchange",
"Routing Key (Optional)": "Routing Key (Optional)",
"Data": "Data",
"Queue": "Queue",
"The name of the exchange to send the message to": "The name of the exchange to send the message to",
"The routing key to use when sending the message": "The routing key to use when sending the message",
"The data to send": "The data to send",
"Message Received": "Message Received",
"Triggers when a message is received on a RabbitMQ queue": "Triggers when a message is received on a RabbitMQ queue",
"Max Messages Per Poll": "Max Messages Per Poll",
"The name of the queue to listen to": "The name of the queue to listen to",
"The maximum number of messages to fetch per poll": "The maximum number of messages to fetch per poll"
}

View File

@@ -0,0 +1,53 @@
import { createPiece, PieceAuth, Property } from '@activepieces/pieces-framework';
import { messageReceived } from './lib/triggers/message-received';
import { sendMessageToExchange } from './lib/actions/send-message-to-exchange';
import { sendMessageToQueue } from './lib/actions/send-message-to-queue';
export const rabbitmqAuth = PieceAuth.CustomAuth({
description: "Rabbitmq Auth",
required: true,
props: {
host: Property.ShortText({
displayName: "Host",
description: "Host",
required: true,
}),
username: Property.ShortText({
displayName: "Username",
description: "Username",
required: true,
}),
password: PieceAuth.SecretText({
displayName: "Password",
description: "Password",
required: true,
}),
port: Property.Number({
displayName: "Port",
description: "Port",
required: true,
}),
vhost: Property.ShortText({
displayName: "Virtual Host",
description: "Virtual Host",
required: false,
}),
},
});
export const rabbitmq = createPiece({
displayName: "RabbitMQ",
auth: rabbitmqAuth,
minimumSupportedRelease: '0.30.0',
logoUrl: "https://cdn.activepieces.com/pieces/rabbitmq.png",
authors: [
"alinperghel"
],
actions: [
sendMessageToExchange,
sendMessageToQueue,
],
triggers: [
messageReceived,
],
});

View File

@@ -0,0 +1,62 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { rabbitmqAuth } from '../..';
import { rabbitmqConnect } from '../common';
export const sendMessageToExchange = createAction({
auth: rabbitmqAuth,
name: 'sendMessageToExchange',
displayName: 'sendMessageToExchange',
description: 'Send a message on a RabbitMQ exchange',
props: {
exchange: Property.ShortText({
displayName: 'Exchange',
description: 'The name of the exchange to send the message to',
required: true,
}),
routingKey: Property.ShortText({
displayName: 'Routing Key (Optional)',
description: 'The routing key to use when sending the message',
required: false,
defaultValue: '',
}),
data: Property.Json({
displayName: 'Data',
description: 'The data to send',
required: true,
defaultValue: {
"key": "value",
"nested": { "key": "value" },
"array": ["value1", "value2"]
},
}),
},
async run(context) {
let connection;
let channel;
try {
const exchange = context.propsValue.exchange;
const routingKey = context.propsValue.routingKey || '';
connection = await rabbitmqConnect(context.auth.props);
channel = await connection.createChannel();
await channel.checkExchange(exchange);
const result = channel.publish(
exchange,
routingKey,
Buffer.from(JSON.stringify(context.propsValue.data))
);
if (!result) {
throw new Error('Failed to send message to exchange');
}
return result;
} finally {
if (channel)
await channel.close();
if (connection)
await connection.close();
}
}
});

View File

@@ -0,0 +1,55 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { rabbitmqAuth } from '../..';
import { rabbitmqConnect } from '../common';
export const sendMessageToQueue = createAction({
auth: rabbitmqAuth,
name: 'sendMessageToQueue',
displayName: 'sendMessageToQueue',
description: 'Send a message on a RabbitMQ queue',
props: {
queue: Property.ShortText({
displayName: 'Queue',
description: 'The name of the exchange to send the message to',
required: true,
}),
data: Property.Json({
displayName: 'Data',
description: 'The data to send',
required: true,
defaultValue: {
"key": "value",
"nested": { "key": "value" },
"array": ["value1", "value2"]
},
}),
},
async run(context) {
const queue = context.propsValue.queue;
let connection;
let channel;
try {
connection = await rabbitmqConnect(context.auth.props);
channel = await connection.createChannel();
await channel.checkQueue(queue);
const result = channel.sendToQueue(
queue,
Buffer.from(JSON.stringify(context.propsValue.data))
);
if (!result) {
throw new Error('Failed to send message to exchange');
}
return result;
} finally {
if (channel) {
await channel.close();
}
if (connection) {
await connection.close();
}
}
}
});

View File

@@ -0,0 +1,24 @@
import { PiecePropValueSchema } from '@activepieces/pieces-framework';
import { rabbitmqAuth } from '../..';
import amqp, { ChannelModel, Connection } from 'amqplib';
export async function rabbitmqConnect(
auth: PiecePropValueSchema<typeof rabbitmqAuth>,
): Promise<ChannelModel> {
return amqp.connect(createAmqpURI(auth), (err: Error, conn: Connection) => {
if (err) {
throw err;
}
return conn;
});
}
function createAmqpURI(auth: PiecePropValueSchema<typeof rabbitmqAuth>): string {
const uri = `amqp://${auth.username}:${auth.password}@${auth.host}:${auth.port}`;
if (!auth.vhost) {
return uri;
}
return `${uri}/${auth.vhost}`;
}

View File

@@ -0,0 +1,88 @@
import {
createTrigger,
TriggerStrategy,
PiecePropValueSchema,
Property,
AppConnectionValueForAuthProperty,
} from '@activepieces/pieces-framework';
import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
import { rabbitmqAuth } from '../../index';
import { rabbitmqConnect } from '../common';
import dayjs from 'dayjs';
const polling: Polling<AppConnectionValueForAuthProperty<typeof rabbitmqAuth>, {
queue: string,
maxMessagesPerPoll: number,
}> = {
strategy: DedupeStrategy.LAST_ITEM,
items: async ({ auth, propsValue }) => {
const connection = await rabbitmqConnect(auth.props);
const channel = await connection.createChannel();
const messages = [];
try {
const queueInfo = await channel.checkQueue(propsValue.queue);
if (queueInfo.messageCount === 0) {
return [];
}
for (let i = 0; i < propsValue.maxMessagesPerPoll; i++) {
const message = await channel.get(propsValue.queue);
if (!message) {
break;
}
messages.push({
id: dayjs().toISOString(),
data: JSON.parse(message.content.toString()),
});
channel.ack(message);
}
} finally {
await channel.close();
await connection.close();
}
return messages;
},
};
export const messageReceived = createTrigger({
auth: rabbitmqAuth,
name: 'messageReceived',
displayName: 'Message Received',
description: 'Triggers when a message is received on a RabbitMQ queue',
props: {
queue: Property.ShortText({
displayName: 'Queue',
description: 'The name of the queue to listen to',
required: true,
}),
maxMessagesPerPoll: Property.Number({
displayName: 'Max Messages Per Poll',
description: 'The maximum number of messages to fetch per poll',
required: true,
defaultValue: 50,
}),
},
sampleData: {},
type: TriggerStrategy.POLLING,
async test(context) {
const { store, auth, propsValue } = context;
return await pollingHelper.test(polling, { store, auth, propsValue, files: context.files });
},
async onEnable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onEnable(polling, { store, auth, propsValue });
},
async onDisable(context) {
const { store, auth, propsValue } = context;
await pollingHelper.onDisable(polling, { store, auth, propsValue });
},
async run(context) {
const { store, auth, propsValue } = context;
return await pollingHelper.poll(polling, { store, auth, propsValue, files: context.files });
},
});

View File

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

View File

@@ -0,0 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"outDir": "../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
"include": ["src/**/*.ts"]
}