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

View File

@@ -0,0 +1,10 @@
{
"name": "@activepieces/piece-recall-ai",
"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-recall-ai",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/recall-ai/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/recall-ai",
"tsConfig": "packages/pieces/community/recall-ai/tsconfig.lib.json",
"packageJson": "packages/pieces/community/recall-ai/package.json",
"main": "packages/pieces/community/recall-ai/src/index.ts",
"assets": [
"packages/pieces/community/recall-ai/*.md",
{
"input": "packages/pieces/community/recall-ai/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/recall-ai",
"command": "bun install --no-save --silent"
}
},
"lint": {
"executor": "@nx/eslint:lint",
"outputs": [
"{options.outputFile}"
]
}
}
}

View File

@@ -0,0 +1,45 @@
{
"API Key": "API Key",
"Server": "Server",
"Your Recall AI API Key.": "Your Recall AI API Key.",
"The Recall AI server to connect to.": "The Recall AI server to connect to.",
"(US) us-east-1": "(US) us-east-1",
"(Pay-as-you-go) us-west-2": "(Pay-as-you-go) us-west-2",
"(EU) eu-central-1": "(EU) eu-central-1",
"(JP) ap-northeast-1": "(JP) ap-northeast-1",
"create bot": "create bot",
"Retrieve Bot": "Retrieve Bot",
"Send Chat Message": "Send Chat Message",
"Custom API Call": "Custom API Call",
"Creates a new bot that will join a meeting": "Creates a new bot that will join a meeting",
"Get details about a specific bot instance": "Get details about a specific bot instance",
"Causes the bot to send a message in the meeting chat": "Causes the bot to send a message in the meeting chat",
"Make a custom API call to a specific endpoint": "Make a custom API call to a specific endpoint",
"Meeting URL": "Meeting URL",
"Bot Name": "Bot Name",
"Bot ID": "Bot ID",
"Message": "Message",
"Send To": "Send To",
"Pin Message": "Pin Message",
"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)",
"The URL of the meeting (e.g., https://zoom.us/j/123?pwd=456)": "The URL of the meeting (e.g., https://zoom.us/j/123?pwd=456)",
"The name of the bot that will be displayed in the call (max 100 characters). Defaults to \"Meeting Notetaker\"": "The name of the bot that will be displayed in the call (max 100 characters). Defaults to \"Meeting Notetaker\"",
"A UUID string identifying the bot": "A UUID string identifying the bot",
"The message that will be sent (max 4096 characters)": "The message that will be sent (max 4096 characters)",
"The person or group that the message will be sent to. Defaults to \"everyone\". On non-Zoom platforms, only \"everyone\" is supported": "The person or group that the message will be sent to. Defaults to \"everyone\". On non-Zoom platforms, only \"everyone\" is supported",
"Whether to pin the message in the chat": "Whether to pin the message in the chat",
"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"
}

View File

@@ -0,0 +1,33 @@
import { createPiece } from '@activepieces/pieces-framework';
import { PieceCategory } from '@activepieces/shared';
import { recallAiAuth } from './lib/common/auth';
import { createBot } from './lib/actions/create-bot';
import { retrieveBot } from './lib/actions/retrieve-bot';
import { sendChatMessage } from './lib/actions/send-chat-message';
import { createCustomApiCallAction } from '@activepieces/pieces-common';
export const recallAi = createPiece({
displayName: 'Recall.ai',
auth: recallAiAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: 'https://cdn.activepieces.com/pieces/recall-ai.png',
categories: [PieceCategory.ARTIFICIAL_INTELLIGENCE],
authors: ['sanket-a11y'],
actions: [
createBot,
retrieveBot,
sendChatMessage,
createCustomApiCallAction({
auth: recallAiAuth,
baseUrl: (auth) => {
return `${(auth)?.props.server as string}/api/v1`;
},
authMapping: async (auth) => {
return {
Authorization: `${auth.props.api_key}`,
};
},
}),
],
triggers: [],
});

View File

@@ -0,0 +1,136 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { recallAiAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const createBot = createAction({
auth: recallAiAuth,
name: 'createBot',
displayName: 'create bot',
description: 'Creates a new bot that will join a meeting',
props: {
meeting_url: Property.ShortText({
displayName: 'Meeting URL',
description:
'The URL of the meeting (e.g., https://zoom.us/j/123?pwd=456)',
required: true,
}),
bot_name: Property.ShortText({
displayName: 'Bot Name',
description:
'The name of the bot that will be displayed in the call (max 100 characters). Defaults to "Meeting Notetaker"',
required: false,
}),
// recording_config: Property.Json({
// displayName: 'Recording Config',
// description:
// 'Configure the recording generated by the bot including transcript options, layout, and when to start recording',
// required: false,
// defaultValue: {},
// }),
// output_media: Property.Json({
// displayName: 'Output Media',
// description:
// 'Settings for the bot output media including video and audio output options',
// required: false,
// }),
// chat: Property.Json({
// displayName: 'Chat',
// description:
// 'Settings for the bot to send chat messages (supported for Zoom, Google Meet, and Microsoft Teams)',
// required: false,
// }),
// automatic_leave: Property.Json({
// displayName: 'Automatic Leave',
// description: 'Configure when the bot automatically leaves the meeting',
// required: false,
// }),
// variant: Property.Json({
// displayName: 'Variant',
// description:
// 'Configure bot variants per meeting platforms (e.g., {"zoom": "web_4_core"})',
// required: false,
// }),
// breakout_room: Property.Json({
// displayName: 'Breakout Room',
// description:
// 'Configure how the bot handles breakout rooms (Zoom only). Options: {"mode": "join_main_room"}, {"mode": "join_specific_room", "room_id": ""}, or {"mode": "auto_accept_all_invites"}',
// required: false,
// }),
// metadata: Property.Json({
// displayName: 'Metadata',
// description: 'Custom metadata to attach to the bot',
// required: false,
// }),
},
async run(context) {
const {
meeting_url,
bot_name,
// recording_config,
// output_media,
// chat,
// automatic_leave,
// variant,
// zoom,
// google_meet,
// breakout_room,
// metadata,
} = context.propsValue;
const body: Record<string, unknown> = {
meeting_url,
};
if (bot_name) {
body['bot_name'] = bot_name;
}
// if (recording_config) {
// body['recording_config'] = recording_config;
// }
// if (output_media) {
// body['output_media'] = output_media;
// }
// if (chat) {
// body['chat'] = chat;
// }
// if (automatic_leave) {
// body['automatic_leave'] = automatic_leave;
// }
// if (variant) {
// body['variant'] = variant;
// }
// if (zoom) {
// body['zoom'] = zoom;
// }
// if (google_meet) {
// body['google_meet'] = google_meet;
// }
// if (breakout_room) {
// body['breakout_room'] = breakout_room;
// }
// if (metadata) {
// body['metadata'] = metadata;
// }
const response = await makeRequest(
context.auth.props.server,
context.auth.props.api_key,
HttpMethod.POST,
'/bot/',
body
);
return response;
},
});

View File

@@ -0,0 +1,31 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { recallAiAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const retrieveBot = createAction({
auth: recallAiAuth,
name: 'retrieveBot',
displayName: 'Retrieve Bot',
description: 'Get details about a specific bot instance',
props: {
bot_id: Property.ShortText({
displayName: 'Bot ID',
description: 'A UUID string identifying the bot',
required: true,
}),
},
async run(context) {
const { bot_id } = context.propsValue;
const response = await makeRequest(
context.auth.props.server,
context.auth.props.api_key,
HttpMethod.GET,
`/bot/${bot_id}`,
{}
);
return response;
},
});

View File

@@ -0,0 +1,60 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { recallAiAuth } from '../common/auth';
import { makeRequest } from '../common/client';
import { HttpMethod } from '@activepieces/pieces-common';
export const sendChatMessage = createAction({
auth: recallAiAuth,
name: 'sendChatMessage',
displayName: 'Send Chat Message',
description: 'Causes the bot to send a message in the meeting chat',
props: {
bot_id: Property.ShortText({
displayName: 'Bot ID',
description: 'A UUID string identifying the bot',
required: true,
}),
message: Property.LongText({
displayName: 'Message',
description: 'The message that will be sent (max 4096 characters)',
required: true,
}),
to: Property.ShortText({
displayName: 'Send To',
description:
'The person or group that the message will be sent to. Defaults to "everyone". On non-Zoom platforms, only "everyone" is supported',
required: false,
}),
pin: Property.Checkbox({
displayName: 'Pin Message',
description: 'Whether to pin the message in the chat',
required: false,
defaultValue: false,
}),
},
async run(context) {
const { bot_id, message, to, pin } = context.propsValue;
const body: Record<string, unknown> = {
message,
};
if (to) {
body['to'] = to;
}
if (pin) {
body['pin'] = pin;
}
const response = await makeRequest(
context.auth.props.server,
context.auth.props.api_key,
HttpMethod.POST,
`/bot/${bot_id}/send_chat_message/`,
body
);
return response;
},
});

View File

@@ -0,0 +1,54 @@
import { PieceAuth, Property } from '@activepieces/pieces-framework';
import { makeRequest } from './client';
import { HttpMethod } from '@activepieces/pieces-common';
export const recallAiAuth = PieceAuth.CustomAuth({
description: 'Your Recall AI API Key.',
required: true,
props: {
api_key: PieceAuth.SecretText({
displayName: 'API Key',
description: 'Your Recall AI API Key.',
required: true,
}),
server: Property.StaticDropdown({
displayName: 'Server',
description: 'The Recall AI server to connect to.',
required: true,
options: {
options: [
{ label: '(US) us-east-1', value: 'https://us-east-1.recall.ai' },
{
label: '(Pay-as-you-go) us-west-2',
value: 'https://us-west-2.recall.ai',
},
{
label: '(EU) eu-central-1',
value: 'https://eu-central-1.recall.ai',
},
{
label: '(JP) ap-northeast-1',
value: 'https://ap-northeast-1.recall.ai',
},
],
},
defaultValue: 'https://us-east-1.recall.ai',
}),
},
validate: async ({ auth }) => {
try {
await makeRequest(
auth.server as string,
auth.api_key as string,
HttpMethod.GET,
'/bot'
);
return { valid: true };
} catch (e) {
return {
valid: false,
error: 'Invalid API Key',
};
}
},
});

View File

@@ -0,0 +1,24 @@
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
export async function makeRequest(
BASE_URL: string,
api_key: string,
method: HttpMethod,
path: string,
body?: unknown
) {
try {
const response = await httpClient.sendRequest({
method,
url: `${BASE_URL}/api/v1${path}`,
headers: {
Authorization: `${api_key}`,
'Content-Type': 'application/json',
},
body,
});
return response.body;
} catch (error: any) {
throw new Error(`Unexpected error: ${error.message || String(error)}`);
}
}

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