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,3 @@
{
"presets": [["@nx/js/babel", { "useBuiltIns": "usage" }]]
}

View File

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

View File

@@ -0,0 +1,7 @@
# pieces-http
This library was generated with [Nx](https://nx.dev).
## Running lint
Run `nx lint pieces-http` to execute the lint via [ESLint](https://eslint.org/).

View File

@@ -0,0 +1,7 @@
{
"name": "@activepieces/piece-http",
"version": "0.10.0",
"dependencies": {
"https-proxy-agent": "7.0.4"
}
}

View File

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

View File

@@ -0,0 +1,33 @@
{
"HTTP": "HTTP",
"Sends HTTP requests and return responses": "Sends HTTP requests and return responses",
"Send HTTP request": "Send HTTP request",
"Method": "Method",
"URL": "URL",
"Headers": "Headers",
"Query params": "Query params",
"Authentication": "Authentication",
"Authentication Fields": "Authentication Fields",
"Body Type": "Body Type",
"Body": "Body",
"Use Proxy": "Use Proxy",
"Proxy Settings": "Proxy Settings",
"Timeout(in seconds)": "Timeout(in seconds)",
"On Failure": "On Failure",
"Use a proxy for this request": "Use a proxy for this request",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"None": "None",
"Basic Auth": "Basic Auth",
"Bearer Token": "Bearer Token",
"Form Data": "Form Data",
"JSON": "JSON",
"Raw": "Raw",
"Retry on all errors (4xx, 5xx)": "Retry on all errors (4xx, 5xx)",
"Continue flow": "Continue flow",
"Retry on internal errors (5xx)": "Retry on internal errors (5xx)"
}

View File

@@ -0,0 +1,38 @@
{
"Sends HTTP requests and return responses": "Sendet HTTP-Anfragen und Rückgabewerte",
"Send HTTP request": "HTTP-Anfrage senden",
"Method": "Methode",
"URL": "URL",
"Headers": "Kopfzeilen",
"Query params": "Abfrageparameter",
"Authentication": "Authentifizierung",
"Authentication Fields": "Authentifizierungsfelder",
"Body Type": "Körpertyp",
"Body": "Körper",
"Response is Binary": "Antwort ist binär",
"Use Proxy": "Proxy verwenden",
"Proxy Settings": "Proxy-Einstellungen",
"Timeout(in seconds)": "Zeitüberschreitung (in Sekunden)",
"On Failure": "Bei Fehlschlag",
"Stop the flow on Failure ?": "Stoppen Sie den Fluss auf Fehler?",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Aktivieren für Dateien wie PDFs, Bilder, etc. Ein base64-Text wird zurückgegeben.",
"Use a proxy for this request": "Proxy für diese Anfrage verwenden",
"GET": "ERHALTEN",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "LÖSCHEN",
"HEAD": "HEAD",
"None": "Keine",
"Basic Auth": "Einfacher Auth",
"Bearer Token": "Bären-Token",
"Form Data": "Formulardaten",
"JSON": "JSON",
"Raw": "Rohe",
"Retry on all errors (4xx, 5xx)": "Alle Fehler wiederholen (4xx, 5xx)",
"Retry on internal errors (5xx)": "Bei internen Fehlern wiederholen (5xx)",
"Do not retry": "Nicht wiederholen",
"Continue flow on all errors": "Flow bei allen Fehlern fortsetzen",
"Continue flow on 4xx errors": "Flow bei 4xx-Fehlern fortsetzen",
"Do not continue (stop the flow)": "Nicht fortfahren (Strömung stoppen)"
}

View File

@@ -0,0 +1,38 @@
{
"Sends HTTP requests and return responses": "Enviar peticiones HTTP y devolver respuestas",
"Send HTTP request": "Enviar solicitud HTTP",
"Method": "Método",
"URL": "URL",
"Headers": "Encabezados",
"Query params": "Parámetros de consulta",
"Authentication": "Autenticación",
"Authentication Fields": "Campos de autenticación",
"Body Type": "Tipo de cuerpo",
"Body": "Cuerpo",
"Response is Binary": "Respuesta es binaria",
"Use Proxy": "Usar proxy",
"Proxy Settings": "Ajustes del proxy",
"Timeout(in seconds)": "Tiempo de espera (en segundos)",
"On Failure": "Al fallar",
"Stop the flow on Failure ?": "¿Detener el flujo en fallo?",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Activar para archivos como PDFs, imágenes, etc. Se devolverá un cuerpo base64.",
"Use a proxy for this request": "Usar un proxy para esta solicitud",
"GET": "RECOGER",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "BORRAR",
"HEAD": "LIMPIO",
"None": "Ninguna",
"Basic Auth": "Auth Básica",
"Bearer Token": "Tóken de portador",
"Form Data": "Datos de Formulario",
"JSON": "JSON",
"Raw": "Rápido",
"Retry on all errors (4xx, 5xx)": "Reintentar en todos los errores (4xx, 5xx)",
"Retry on internal errors (5xx)": "Reintentar en errores internos (5xx)",
"Do not retry": "No reintentar",
"Continue flow on all errors": "Continuar el flujo en todos los errores",
"Continue flow on 4xx errors": "Continuar flujo en errores 4xx",
"Do not continue (stop the flow)": "No continuar (detener el flujo)"
}

View File

@@ -0,0 +1,38 @@
{
"Sends HTTP requests and return responses": "Envoie des requêtes HTTP et retourne des réponses",
"Send HTTP request": "Envoyer une requête HTTP",
"Method": "Méthode",
"URL": "URL",
"Headers": "Headers",
"Query params": "Paramètres de requête",
"Authentication": "Authentification",
"Authentication Fields": "Champs d'authentification",
"Body Type": "Body Type",
"Body": "Body",
"Response is Binary": "La réponse est binaire",
"Use Proxy": "Utiliser le proxy",
"Proxy Settings": "Paramètres du proxy",
"Timeout(in seconds)": "Délai d'attente (en secondes)",
"On Failure": "En cas d'échec",
"Stop the flow on Failure ?": "Arrêter le Flow en cas d'échec ?",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Activer pour les fichiers comme les PDFs, les images, etc. Un body en base64 sera retourné.",
"Use a proxy for this request": "Utiliser un proxy pour cette requête",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"None": "Aucun",
"Basic Auth": "Authentification basique",
"Bearer Token": "Bearer Token",
"Form Data": "Données du formulaire",
"JSON": "JSON",
"Raw": "Brute",
"Retry on all errors (4xx, 5xx)": "Réessayer pour toutes les erreurs (4xx, 5xx)",
"Retry on internal errors (5xx)": "Réessayer en cas d'erreurs internes (5xx)",
"Do not retry": "Ne pas réessayer",
"Continue flow on all errors": "Poursuivre le Flow pour toutes les erreurs",
"Continue flow on 4xx errors": "Poursuivre le Flow en cas d'erreurs 4xx",
"Do not continue (stop the flow)": "Ne pas continuer (arrêter le Flow)"
}

View File

@@ -0,0 +1,33 @@
{
"HTTP": "HTTP",
"Sends HTTP requests and return responses": "Sends HTTP requests and return responses",
"Send HTTP request": "Send HTTP request",
"Method": "Method",
"URL": "URL",
"Headers": "Headers",
"Query params": "Query params",
"Authentication": "Authentication",
"Authentication Fields": "Authentication Fields",
"Body Type": "Body Type",
"Body": "Body",
"Use Proxy": "Use Proxy",
"Proxy Settings": "Proxy Settings",
"Timeout(in seconds)": "Timeout(in seconds)",
"On Failure": "On Failure",
"Use a proxy for this request": "Use a proxy for this request",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"None": "None",
"Basic Auth": "Basic Auth",
"Bearer Token": "Bearer Token",
"Form Data": "Form Data",
"JSON": "JSON",
"Raw": "Raw",
"Retry on all errors (4xx, 5xx)": "Retry on all errors (4xx, 5xx)",
"Continue flow": "Continue flow",
"Retry on internal errors (5xx)": "Retry on internal errors (5xx)"
}

View File

@@ -0,0 +1,33 @@
{
"HTTP": "HTTP",
"Sends HTTP requests and return responses": "Sends HTTP requests and return responses",
"Send HTTP request": "Send HTTP request",
"Method": "Method",
"URL": "URL",
"Headers": "Headers",
"Query params": "Query params",
"Authentication": "Authentication",
"Authentication Fields": "Authentication Fields",
"Body Type": "Body Type",
"Body": "Body",
"Use Proxy": "Use Proxy",
"Proxy Settings": "Proxy Settings",
"Timeout(in seconds)": "Timeout(in seconds)",
"On Failure": "On Failure",
"Use a proxy for this request": "Use a proxy for this request",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"None": "None",
"Basic Auth": "Basic Auth",
"Bearer Token": "Bearer Token",
"Form Data": "Form Data",
"JSON": "JSON",
"Raw": "Raw",
"Retry on all errors (4xx, 5xx)": "Retry on all errors (4xx, 5xx)",
"Continue flow": "Continue flow",
"Retry on internal errors (5xx)": "Retry on internal errors (5xx)"
}

View File

@@ -0,0 +1,38 @@
{
"Sends HTTP requests and return responses": "HTTPリクエストとレスポンスを送信する",
"Send HTTP request": "HTTPリクエストを送信",
"Method": "方法",
"URL": "URL",
"Headers": "ヘッダー",
"Query params": "クエリパラメータ",
"Authentication": "認証",
"Authentication Fields": "認証フィールド",
"Body Type": "ボディタイプ",
"Body": "本文",
"Response is Binary": "応答はバイナリです",
"Use Proxy": "プロキシを使用",
"Proxy Settings": "プロキシ設定",
"Timeout(in seconds)": "タイムアウト(秒単位)",
"On Failure": "失敗時",
"Stop the flow on Failure ?": "失敗時の流れを停止しますか?",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "PDF、画像などのファイルを有効にする base64ボディが返されます。",
"Use a proxy for this request": "このリクエストにプロキシを使用する",
"GET": "取得",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "削除",
"HEAD": "頭",
"None": "なし",
"Basic Auth": "ベーシック認証",
"Bearer Token": "ベアラートトークン",
"Form Data": "フォームデータ",
"JSON": "JSON",
"Raw": "Raw",
"Retry on all errors (4xx, 5xx)": "すべてのエラー4xxx、5xxを再試行してください",
"Retry on internal errors (5xx)": "内部エラーを再試行5xx",
"Do not retry": "再試行しない",
"Continue flow on all errors": "すべてのエラーでフローを続ける",
"Continue flow on 4xx errors": "4xxエラー時にフローを続ける",
"Do not continue (stop the flow)": "続行しない (フローを停止する)"
}

View File

@@ -0,0 +1,38 @@
{
"Sends HTTP requests and return responses": "Verstuurt HTTP-verzoeken en retourantwoorden",
"Send HTTP request": "Stuur HTTP request",
"Method": "Methode",
"URL": "URL",
"Headers": "Kopteksten",
"Query params": "Query parameters",
"Authentication": "Authenticatie",
"Authentication Fields": "Authenticatie velden",
"Body Type": "Type lichaam",
"Body": "Lichaam",
"Response is Binary": "Antwoord is binair",
"Use Proxy": "Gebruik Proxy",
"Proxy Settings": "Proxy Instellingen",
"Timeout(in seconds)": "Timeout(in seconden)",
"On Failure": "Bij Mislukking",
"Stop the flow on Failure ?": "Stop de stroom bij mislukking?",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Inschakelen voor bestanden zoals PDF's, afbeeldingen, etc. Een base64 inhoud wordt geretourneerd.",
"Use a proxy for this request": "Gebruik een proxy voor dit verzoek",
"GET": "KRIJG",
"POST": "POSTE",
"PATCH": "BEKIJK",
"PUT": "PUT",
"DELETE": "VERWIJDEREN",
"HEAD": "HOOFD",
"None": "geen",
"Basic Auth": "Basis authenticatie",
"Bearer Token": "Betere Token",
"Form Data": "Formulieren gegevens",
"JSON": "JSON",
"Raw": "Onbewerkte",
"Retry on all errors (4xx, 5xx)": "Opnieuw proberen bij alle fouten (4xx, 5xx)",
"Retry on internal errors (5xx)": "Opnieuw proberen bij interne fouten (5xx)",
"Do not retry": "Probeer het niet opnieuw",
"Continue flow on all errors": "Doorgaan met flow op alle fouten",
"Continue flow on 4xx errors": "Doorgaan met stroom op 4xx fouten",
"Do not continue (stop the flow)": "Ga niet verder (stop de stroom)"
}

View File

@@ -0,0 +1,38 @@
{
"Sends HTTP requests and return responses": "Envia requisições HTTP e respostas de retorno",
"Send HTTP request": "Enviar solicitação HTTP",
"Method": "Método",
"URL": "URL:",
"Headers": "Cabeçalhos",
"Query params": "Consultar parâmetros",
"Authentication": "Autenticação",
"Authentication Fields": "Campos de autenticação",
"Body Type": "Tipo de Corpo",
"Body": "Conteúdo",
"Response is Binary": "Resposta é Binária",
"Use Proxy": "Usar Proxy",
"Proxy Settings": "Configurações do Proxy",
"Timeout(in seconds)": "Tempo limite (em segundos)",
"On Failure": "Em caso de falha",
"Stop the flow on Failure ?": "Parar fluxo falhar?",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Ative para arquivos como PDFs, imagens, etc. Um corpo base64 será retornado.",
"Use a proxy for this request": "Usar um proxy para esta requisição",
"GET": "OBTER",
"POST": "POSTAR",
"PATCH": "COMPRAR",
"PUT": "COLOCAR",
"DELETE": "EXCLUIR",
"HEAD": "CABEÇA",
"None": "Nenhuma",
"Basic Auth": "Autenticação básica",
"Bearer Token": "Token do portador",
"Form Data": "Dados de Formulário",
"JSON": "JSON",
"Raw": "RAW",
"Retry on all errors (4xx, 5xx)": "Repetir todos os erros (4xx, 5xx)",
"Retry on internal errors (5xx)": "Tentar novamente em erros internos (5xx)",
"Do not retry": "Não tente novamente",
"Continue flow on all errors": "Continuar fluxo em todos os erros",
"Continue flow on 4xx errors": "Continuar fluxo em erros de 4xx",
"Do not continue (stop the flow)": "Não continue (pare o fluxo)"
}

View File

@@ -0,0 +1,35 @@
{
"HTTP": "HTTP",
"Sends HTTP requests and return responses": "Отправляет HTTP запросы и возвращает ответы",
"Send HTTP request": "Отправить HTTP-запрос",
"Method": "Метод",
"URL": "URL",
"Headers": "Заголовки",
"Query params": "Параметры запроса",
"Authentication": "Проверка подлинности",
"Authentication Fields": "Поля аутентификации",
"Body Type": "Тип тела",
"Body": "Тело",
"Response is Binary": "Ответ является двоичным",
"Use Proxy": "Использовать прокси",
"Proxy Settings": "Настройки прокси",
"Timeout(in seconds)": "Тайм-аут (в секундах)",
"On Failure": "При ошибке",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Включить для файлов типа PDF, изображений и т. д. Будет возвращено тело base64.",
"Use a proxy for this request": "Использовать прокси для этого запроса",
"GET": "ПОЛУЧИТЬ",
"POST": "ПОСТ",
"PATCH": "ПАТЧ",
"PUT": "ПОКУПИТЬ",
"DELETE": "УДАЛИТЬ",
"HEAD": "HEAD",
"None": "Нет",
"Basic Auth": "Базовая авторизация",
"Bearer Token": "Жетон носителя",
"Form Data": "Данные формы",
"JSON": "JSON",
"Raw": "Сырье",
"Retry on all errors (4xx, 5xx)": "Повторить все ошибки (4xx, 5xx)",
"Continue flow": "Продолжить поток",
"Retry on internal errors (5xx)": "Повторить внутренние ошибки (5xx)"
}

View File

@@ -0,0 +1,38 @@
{
"Sends HTTP requests and return responses": "Sends HTTP requests and return responses",
"Send HTTP request": "Send HTTP request",
"Method": "Method",
"URL": "URL",
"Headers": "Headers",
"Query params": "Query params",
"Authentication": "Authentication",
"Authentication Fields": "Authentication Fields",
"Body Type": "Body Type",
"Body": "Body",
"Response is Binary": "Response is Binary",
"Use Proxy": "Use Proxy",
"Proxy Settings": "Proxy Settings",
"Timeout(in seconds)": "Timeout(in seconds)",
"On Failure": "On Failure",
"Stop the flow on Failure ?": "Stop the flow on Failure ?",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Enable for files like PDFs, images, etc. A base64 body will be returned.",
"Use a proxy for this request": "Use a proxy for this request",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"None": "None",
"Basic Auth": "Basic Auth",
"Bearer Token": "Bearer Token",
"Form Data": "Form Data",
"JSON": "JSON",
"Raw": "Raw",
"Retry on all errors (4xx, 5xx)": "Retry on all errors (4xx, 5xx)",
"Retry on internal errors (5xx)": "Retry on internal errors (5xx)",
"Do not retry": "Do not retry",
"Continue flow on all errors": "Continue flow on all errors",
"Continue flow on 4xx errors": "Continue flow on 4xx errors",
"Do not continue (stop the flow)": "Do not continue (stop the flow)"
}

View File

@@ -0,0 +1,35 @@
{
"HTTP": "HTTP",
"Sends HTTP requests and return responses": "Sends HTTP requests and return responses",
"Send HTTP request": "Send HTTP request",
"Method": "Method",
"URL": "URL",
"Headers": "Headers",
"Query params": "Query params",
"Authentication": "Authentication",
"Authentication Fields": "Authentication Fields",
"Body Type": "Body Type",
"Body": "Body",
"Response is Binary": "Response is Binary",
"Use Proxy": "Use Proxy",
"Proxy Settings": "Proxy Settings",
"Timeout(in seconds)": "Timeout(in seconds)",
"On Failure": "On Failure",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Enable for files like PDFs, images, etc. A base64 body will be returned.",
"Use a proxy for this request": "Use a proxy for this request",
"GET": "GET",
"POST": "POST",
"PATCH": "PATCH",
"PUT": "PUT",
"DELETE": "DELETE",
"HEAD": "HEAD",
"None": "None",
"Basic Auth": "Basic Auth",
"Bearer Token": "Bearer Token",
"Form Data": "Form Data",
"JSON": "JSON",
"Raw": "Raw",
"Retry on all errors (4xx, 5xx)": "Retry on all errors (4xx, 5xx)",
"Continue flow": "Continue flow",
"Retry on internal errors (5xx)": "Retry on internal errors (5xx)"
}

View File

@@ -0,0 +1,38 @@
{
"Sends HTTP requests and return responses": "Sends HTTP requests and return responses",
"Send HTTP request": "Send HTTP request",
"Method": "方法",
"URL": "URL",
"Headers": "信头",
"Query params": "Query params",
"Authentication": "认证",
"Authentication Fields": "身份验证字段",
"Body Type": "Body Type",
"Body": "正文内容",
"Response is Binary": "Response is Binary",
"Use Proxy": "Use Proxy",
"Proxy Settings": "Proxy Settings",
"Timeout(in seconds)": "Timeout(in seconds)",
"On Failure": "On Failure",
"Stop the flow on Failure ?": "Stop the flow on Failure ?",
"Enable for files like PDFs, images, etc. A base64 body will be returned.": "Enable for files like PDFs, images, etc. A base64 body will be returned.",
"Use a proxy for this request": "Use a proxy for this request",
"GET": "获取",
"POST": "帖子",
"PATCH": "PATCH",
"PUT": "弹出",
"DELETE": "删除",
"HEAD": "黑色",
"None": "无",
"Basic Auth": "基本认证",
"Bearer Token": "Bearer Token",
"Form Data": "表单数据",
"JSON": "JSON",
"Raw": "原始文件",
"Retry on all errors (4xx, 5xx)": "Retry on all errors (4xx, 5xx)",
"Retry on internal errors (5xx)": "Retry on internal errors (5xx)",
"Do not retry": "Do not retry",
"Continue flow on all errors": "Continue flow on all errors",
"Continue flow on 4xx errors": "Continue flow on 4xx errors",
"Do not continue (stop the flow)": "Do not continue (stop the flow)"
}

View File

@@ -0,0 +1,25 @@
import { PieceAuth, createPiece } from '@activepieces/pieces-framework';
import { PieceCategory } from '@activepieces/shared';
import { httpSendRequestAction } from './lib/actions/send-http-request-action';
export const http = createPiece({
displayName: 'HTTP',
description: 'Sends HTTP requests and return responses',
logoUrl: 'https://cdn.activepieces.com/pieces/http.png',
categories: [PieceCategory.CORE],
auth: PieceAuth.None(),
minimumSupportedRelease: '0.20.3',
actions: [httpSendRequestAction],
authors: [
'bibhuty-did-this',
'landonmoir',
'JanHolger',
'Salem-Alaa',
'kishanprmr',
'AbdulTheActivePiecer',
'khaledmashaly',
'abuaboud',
'pfernandez98',
],
triggers: [],
});

View File

@@ -0,0 +1,446 @@
import {
httpClient,
HttpError,
HttpHeaders,
HttpRequest,
QueryParams,
AuthenticationType,
} from '@activepieces/pieces-common';
import {
ApFile,
createAction,
DynamicPropsValue,
PieceAuth,
Property,
} from '@activepieces/pieces-framework';
import { assertNotNullOrUndefined, isEmpty } from '@activepieces/shared';
import FormData from 'form-data';
import { httpMethodDropdown } from '../common/props';
import { HttpsProxyAgent } from 'https-proxy-agent';
import axios from 'axios';
enum AuthType {
NONE = 'NONE',
BASIC = AuthenticationType.BASIC,
BEARER_TOKEN = AuthenticationType.BEARER_TOKEN,
}
export const httpSendRequestAction = createAction({
name: 'send_request',
displayName: 'Send HTTP request',
description: 'Send HTTP request',
props: {
method: httpMethodDropdown,
url: Property.ShortText({
displayName: 'URL',
required: true,
}),
headers: Property.Object({
displayName: 'Headers',
required: true,
}),
queryParams: Property.Object({
displayName: 'Query params',
required: true,
}),
authType: Property.StaticDropdown<AuthType>({
displayName: 'Authentication',
required: true,
defaultValue: AuthType.NONE,
options: {
disabled: false,
options: [
{ label: 'None', value: AuthType.NONE },
{ label: 'Basic Auth', value: AuthType.BASIC },
{ label: 'Bearer Token', value: AuthType.BEARER_TOKEN },
],
},
}),
authFields: Property.DynamicProperties({
displayName: 'Authentication Fields',
required: false,
auth: PieceAuth.None(),
refreshers: ['authType'],
props: async ({ authType }) => {
if (!authType) {
return {};
}
const authTypeEnum = authType.toString() as AuthType;
let fields: DynamicPropsValue = {};
switch (authTypeEnum) {
case AuthType.NONE:
fields = {};
break;
case AuthType.BASIC:
fields = {
username: Property.ShortText({
displayName: 'Username',
description: 'The username to use for authentication.',
required: true,
}),
password: Property.ShortText({
displayName: 'Password',
description: 'The password to use for authentication.',
required: true,
}),
};
break;
case AuthType.BEARER_TOKEN:
fields = {
token: Property.ShortText({
displayName: 'Token',
description: 'The Bearer token to use for authentication.',
required: true,
}),
};
break;
default:
throw new Error('Invalid authentication type');
}
return fields;
},
}),
body_type: Property.StaticDropdown({
displayName: 'Body Type',
required: false,
defaultValue: 'none',
options: {
disabled: false,
options: [
{
label: 'None',
value: 'none',
},
{
label: 'Form Data',
value: 'form_data',
},
{
label: 'JSON',
value: 'json',
},
{
label: 'Raw',
value: 'raw',
},
],
},
}),
body: Property.DynamicProperties({
displayName: 'Body',
refreshers: ['body_type'],
required: false,
auth: PieceAuth.None(),
props: async ({ body_type }) => {
if (!body_type) return {};
const bodyTypeInput = body_type as unknown as string;
const fields: DynamicPropsValue = {};
switch (bodyTypeInput) {
case 'none':
break;
case 'json':
fields['data'] = Property.Json({
displayName: 'JSON Body',
required: true,
});
break;
case 'raw':
fields['data'] = Property.LongText({
displayName: 'Raw Body',
required: true,
});
break;
case 'form_data':
fields['data'] = Property.Array({
displayName: 'Form Data',
required: true,
properties: {
fieldName: Property.ShortText({
displayName: 'Field Name',
required: true
}),
fieldType: Property.StaticDropdown({
displayName: 'Field Type',
required: true,
options: {
disabled: false,
options: [
{ label: 'Text', value: 'text' },
{ label: 'File', value: 'file' }
]
}
}),
textFieldValue: Property.LongText({
displayName: 'Text Field Value',
required: false
}),
fileFieldValue: Property.File({
displayName: 'File Field Value',
required: false
})
}
});
break;
}
return fields;
},
}),
response_is_binary: Property.Checkbox({
displayName: 'Response is Binary',
description:
'Enable for files like PDFs, images, etc. A base64 body will be returned.',
required: false,
defaultValue: false,
}),
use_proxy: Property.Checkbox({
displayName: 'Use Proxy',
defaultValue: false,
description: 'Use a proxy for this request',
required: false,
}),
proxy_settings: Property.DynamicProperties({
auth: PieceAuth.None(),
displayName: 'Proxy Settings',
refreshers: ['use_proxy'],
required: false,
props: async ({ use_proxy }) => {
if (!use_proxy) return {};
const fields: DynamicPropsValue = {};
fields['proxy_host'] = Property.ShortText({
displayName: 'Proxy Host',
required: true,
});
fields['proxy_port'] = Property.Number({
displayName: 'Proxy Port',
required: true,
});
fields['proxy_username'] = Property.ShortText({
displayName: 'Proxy Username',
required: false,
});
fields['proxy_password'] = Property.ShortText({
displayName: 'Proxy Password',
required: false,
});
return fields;
},
}),
timeout: Property.Number({
displayName: 'Timeout(in seconds)',
required: false,
}),
failureMode: Property.StaticDropdown({
displayName: 'On Failure',
required: false,
defaultValue: 'continue_none',
options: {
disabled: false,
options: [
{ label: 'Retry on all errors (4xx, 5xx)', value: 'retry_all' },
{ label: 'Retry on internal errors (5xx)', value: 'retry_5xx' },
{ label: 'Do not retry', value: 'retry_none' },
{ label: 'Continue flow on all errors', value: 'continue_all' },
{ label: 'Continue flow on 4xx errors', value: 'continue_4xx' },
{ label: 'Do not continue (stop the flow)', value: 'continue_none' },
],
},
}),
stopFlow: Property.Checkbox({
displayName: 'Stop the flow on Failure ?',
required: false,
}),
},
errorHandlingOptions: {
continueOnFailure: { hide: true, defaultValue: false },
retryOnFailure: { hide: true, defaultValue: false },
},
async run(context) {
const {
method,
url,
headers,
queryParams,
body,
body_type,
response_is_binary,
timeout,
failureMode,
use_proxy,
authType,
authFields,
stopFlow,
} = context.propsValue;
assertNotNullOrUndefined(method, 'Method');
assertNotNullOrUndefined(url, 'URL');
const request: HttpRequest = {
method,
url,
headers: headers as HttpHeaders,
queryParams: queryParams as QueryParams,
timeout: timeout ? timeout * 1000 : 0,
};
switch (authType) {
case AuthType.BASIC:
if (authFields) {
request.authentication = {
username: authFields['username'],
password: authFields['password'],
type: AuthenticationType.BASIC,
};
}
break;
case AuthType.BEARER_TOKEN:
if (authFields) {
request.authentication = {
token: authFields['token'],
type: AuthenticationType.BEARER_TOKEN,
};
}
break;
}
// Set response type to arraybuffer if binary response is expected
if (response_is_binary) {
request.responseType = 'arraybuffer';
}
if (body) {
const bodyInput = body['data'];
if (body_type === 'form_data') {
const formBodyInput = bodyInput as Array<{
fieldName: string;
fieldType: 'text' | 'file';
textFieldValue?: string;
fileFieldValue?: ApFile;
}>;
const formData = new FormData();
for (const { fieldName, fieldType, textFieldValue, fileFieldValue } of formBodyInput) {
if (fieldType === 'text' && !isEmpty(textFieldValue)) {
formData.append(fieldName, textFieldValue);
} else if (fieldType === 'file' && !isEmpty(fileFieldValue)) {
formData.append(fieldName, fileFieldValue!.data,{filename:fileFieldValue?.filename});
}
}
request.body = formData;
request.headers = { ...request.headers, ...formData.getHeaders() };
} else {
request.body = bodyInput;
}
}
const apiRequest = async () => {
if (use_proxy) {
const proxySettings = context.propsValue.proxy_settings;
assertNotNullOrUndefined(proxySettings, 'Proxy Settings');
assertNotNullOrUndefined(proxySettings['proxy_host'], 'Proxy Host');
assertNotNullOrUndefined(proxySettings['proxy_port'], 'Proxy Port');
let proxyUrl;
if (proxySettings.proxy_username && proxySettings.proxy_password) {
proxyUrl = `http://${proxySettings.proxy_username}:${proxySettings.proxy_password}@${proxySettings.proxy_host}:${proxySettings.proxy_port}`;
} else {
proxyUrl = `http://${proxySettings.proxy_host}:${proxySettings.proxy_port}`;
}
const httpsAgent = new HttpsProxyAgent(proxyUrl);
const axiosClient = axios.create({
httpsAgent,
});
return await httpClient.sendRequest(request, axiosClient);
}
return await httpClient.sendRequest(request);
};
let attempts = 0;
while (attempts < 3) {
try {
const response = await apiRequest();
return handleBinaryResponse(
response.body,
response.status,
response.headers,
response_is_binary
);
} catch (error) {
attempts++;
if (stopFlow) {
throw error;
}
switch (failureMode) {
case 'retry_all': {
if (attempts < 3) continue;
throw error;
}
case 'retry_5xx': {
if (
(error as HttpError).response.status >= 500 &&
(error as HttpError).response.status < 600
) {
if (attempts < 3) continue;
throw error; // after 3 tries, throw
}
return (error as HttpError).errorMessage(); //throw error; // non 5xxx error
}
case 'continue_all':
return (error as HttpError).errorMessage();
case 'continue_4xx':
if (
(error as HttpError).response?.status >= 400 &&
(error as HttpError).response?.status < 500
) {
return (error as HttpError).errorMessage();
}
if (attempts < 3) continue;
throw error;
case 'continue_none':
throw error;
default:
throw error;
}
}
}
throw new Error('Unexpected error occured');
},
});
const handleBinaryResponse = (
bodyContent: string | ArrayBuffer | Buffer,
status: number,
headers?: HttpHeaders,
isBinary?: boolean
) => {
let body;
if (isBinary && isBinaryBody(bodyContent)) {
body = Buffer.from(bodyContent as unknown as string).toString('base64');
} else {
body = bodyContent;
}
return { status, headers, body };
};
const isBinaryBody = (body: string | ArrayBuffer | Buffer) => {
return body instanceof ArrayBuffer || Buffer.isBuffer(body);
};

View File

@@ -0,0 +1,13 @@
import { Property } from '@activepieces/pieces-framework';
import { HttpMethod } from '@activepieces/pieces-common';
const httpMethodDropdownOptions = Object.values(HttpMethod).map((m) => ({
label: m,
value: m,
}));
export const httpMethodDropdown = Property.StaticDropdown<HttpMethod>({
displayName: 'Method',
required: true,
options: { options: httpMethodDropdownOptions },
});

View File

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

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"]
}