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:
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"extends": [
|
||||
"../../../../.eslintrc.base.json"
|
||||
],
|
||||
"ignorePatterns": [
|
||||
"!**/*"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx",
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.ts",
|
||||
"*.tsx"
|
||||
],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"*.js",
|
||||
"*.jsx"
|
||||
],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
# pieces-ask-handle
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build pieces-ask-handle` to build the library.
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@activepieces/piece-ask-handle",
|
||||
"version": "0.0.2",
|
||||
"type": "commonjs",
|
||||
"main": "./src/index.js",
|
||||
"types": "./src/index.d.ts",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"name": "pieces-ask-handle",
|
||||
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "packages/pieces/community/ask-handle/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/ask-handle",
|
||||
"tsConfig": "packages/pieces/community/ask-handle/tsconfig.lib.json",
|
||||
"packageJson": "packages/pieces/community/ask-handle/package.json",
|
||||
"main": "packages/pieces/community/ask-handle/src/index.ts",
|
||||
"assets": [
|
||||
"packages/pieces/community/ask-handle/*.md",
|
||||
{
|
||||
"input": "packages/pieces/community/ask-handle/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/ask-handle",
|
||||
"command": "bun install --no-save --silent"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint",
|
||||
"outputs": [
|
||||
"{options.outputFile}"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"\nTo get your API Key:\n\n1. Go to https://dashboard.askhandle.com\n2. Sign in to your account\n3. Navigate to API settings\n4. Create or copy your API token\n5. Paste it here\n": "\nTo get your API Key:\n\n1. Go to https://dashboard.askhandle.com\n2. Sign in to your account\n3. Navigate to API settings\n4. Create or copy your API token\n5. Paste it here\n",
|
||||
"Create Message": "Create Message",
|
||||
"Create Lead": "Create Lead",
|
||||
"List Rooms": "List Rooms",
|
||||
"List Leads": "List Leads",
|
||||
"Send a message to a room": "Send a message to a room",
|
||||
"Create a new lead": "Create a new lead",
|
||||
"Get a list of all rooms": "Get a list of all rooms",
|
||||
"Get a list of all leads": "Get a list of all leads",
|
||||
"Room": "Room",
|
||||
"Message": "Message",
|
||||
"Nickname": "Nickname",
|
||||
"Email": "Email",
|
||||
"Phone Number": "Phone Number",
|
||||
"Device": "Device",
|
||||
"From Page Title": "From Page Title",
|
||||
"Referrer": "Referrer",
|
||||
"Start Date": "Start Date",
|
||||
"End Date": "End Date",
|
||||
"Limit": "Limit",
|
||||
"Select a room": "Select a room",
|
||||
"The message content": "The message content",
|
||||
"Sender nickname": "Sender nickname",
|
||||
"Sender email": "Sender email",
|
||||
"Sender phone number": "Sender phone number",
|
||||
"Lead nickname": "Lead nickname",
|
||||
"Lead email": "Lead email",
|
||||
"Lead phone number": "Lead phone number",
|
||||
"Device information": "Device information",
|
||||
"Page title where lead originated": "Page title where lead originated",
|
||||
"Referrer URL": "Referrer URL",
|
||||
"Filter leads from this date": "Filter leads from this date",
|
||||
"Filter leads until this date": "Filter leads until this date",
|
||||
"Maximum number of leads to return": "Maximum number of leads to return",
|
||||
"New Message": "New Message",
|
||||
"New Lead": "New Lead",
|
||||
"New Room": "New Room",
|
||||
"Triggers when a new message is received": "Triggers when a new message is received",
|
||||
"Triggers when a new lead is created": "Triggers when a new lead is created",
|
||||
"Triggers when a new room is created": "Triggers when a new room is created"
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { createPiece } from "@activepieces/pieces-framework";
|
||||
import { askHandleAuth } from "./lib/common/auth";
|
||||
import { createMessage } from "./lib/actions/create-message";
|
||||
import { createLead } from "./lib/actions/create-lead";
|
||||
import { listRooms } from "./lib/actions/list-rooms";
|
||||
import { listLeads } from "./lib/actions/list-leads";
|
||||
import { newMessageTrigger } from "./lib/triggers/new-message";
|
||||
import { newLeadTrigger } from "./lib/triggers/new-lead";
|
||||
import { newRoomTrigger } from "./lib/triggers/new-room";
|
||||
|
||||
export const askHandle = createPiece({
|
||||
displayName: "AskHandle",
|
||||
auth: askHandleAuth,
|
||||
minimumSupportedRelease: '0.36.1',
|
||||
logoUrl: "https://cdn.activepieces.com/pieces/ask-handle.png",
|
||||
authors: ["onyedikachi-david"],
|
||||
actions: [
|
||||
createMessage,
|
||||
createLead,
|
||||
listRooms,
|
||||
listLeads,
|
||||
],
|
||||
triggers: [
|
||||
newMessageTrigger,
|
||||
newLeadTrigger,
|
||||
newRoomTrigger,
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { askHandleAuth } from '../common/auth';
|
||||
import { askHandleApiCall } from '../common/client';
|
||||
|
||||
export const createLead = createAction({
|
||||
auth: askHandleAuth,
|
||||
name: 'create_lead',
|
||||
displayName: 'Create Lead',
|
||||
description: 'Create a new lead',
|
||||
props: {
|
||||
nickname: Property.ShortText({
|
||||
displayName: 'Nickname',
|
||||
description: 'Lead nickname',
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: 'Lead email',
|
||||
required: false,
|
||||
}),
|
||||
phone_number: Property.ShortText({
|
||||
displayName: 'Phone Number',
|
||||
description: 'Lead phone number',
|
||||
required: false,
|
||||
}),
|
||||
device: Property.ShortText({
|
||||
displayName: 'Device',
|
||||
description: 'Device information',
|
||||
required: false,
|
||||
}),
|
||||
from_page_title: Property.ShortText({
|
||||
displayName: 'From Page Title',
|
||||
description: 'Page title where lead originated',
|
||||
required: false,
|
||||
}),
|
||||
referrer: Property.ShortText({
|
||||
displayName: 'Referrer',
|
||||
description: 'Referrer URL',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const {
|
||||
nickname,
|
||||
email,
|
||||
phone_number,
|
||||
device,
|
||||
from_page_title,
|
||||
referrer,
|
||||
} = context.propsValue;
|
||||
|
||||
const payload: any = {};
|
||||
|
||||
if (nickname) payload.nickname = nickname;
|
||||
if (email) payload.email = email;
|
||||
if (phone_number) payload.phone_number = phone_number;
|
||||
if (device) payload.device = device;
|
||||
if (from_page_title) payload.from_page_title = from_page_title;
|
||||
if (referrer) payload.referrer = referrer;
|
||||
|
||||
return await askHandleApiCall(
|
||||
context.auth.secret_text,
|
||||
HttpMethod.POST,
|
||||
'/leads/',
|
||||
payload
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { askHandleAuth } from '../common/auth';
|
||||
import { askHandleApiCall } from '../common/client';
|
||||
import { roomDropdown } from '../common/props';
|
||||
|
||||
export const createMessage = createAction({
|
||||
auth: askHandleAuth,
|
||||
name: 'create_message',
|
||||
displayName: 'Create Message',
|
||||
description: 'Send a message to a room',
|
||||
props: {
|
||||
room: roomDropdown,
|
||||
body: Property.LongText({
|
||||
displayName: 'Message',
|
||||
description: 'The message content',
|
||||
required: true,
|
||||
}),
|
||||
nickname: Property.ShortText({
|
||||
displayName: 'Nickname',
|
||||
description: 'Sender nickname',
|
||||
required: false,
|
||||
}),
|
||||
email: Property.ShortText({
|
||||
displayName: 'Email',
|
||||
description: 'Sender email',
|
||||
required: false,
|
||||
}),
|
||||
phone_number: Property.ShortText({
|
||||
displayName: 'Phone Number',
|
||||
description: 'Sender phone number',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { room, body, nickname, email, phone_number } = context.propsValue;
|
||||
|
||||
const payload: any = {
|
||||
body,
|
||||
room: {
|
||||
uuid: room,
|
||||
},
|
||||
};
|
||||
|
||||
if (nickname) payload.nickname = nickname;
|
||||
if (email) payload.email = email;
|
||||
if (phone_number) payload.phone_number = phone_number;
|
||||
|
||||
return await askHandleApiCall(
|
||||
context.auth.secret_text,
|
||||
HttpMethod.POST,
|
||||
'/messages/',
|
||||
payload
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { askHandleAuth } from '../common/auth';
|
||||
import { askHandleApiCall } from '../common/client';
|
||||
|
||||
export const listLeads = createAction({
|
||||
auth: askHandleAuth,
|
||||
name: 'list_leads',
|
||||
displayName: 'List Leads',
|
||||
description: 'Get a list of all leads',
|
||||
props: {
|
||||
start_date: Property.DateTime({
|
||||
displayName: 'Start Date',
|
||||
description: 'Filter leads from this date',
|
||||
required: false,
|
||||
}),
|
||||
end_date: Property.DateTime({
|
||||
displayName: 'End Date',
|
||||
description: 'Filter leads until this date',
|
||||
required: false,
|
||||
}),
|
||||
limit: Property.Number({
|
||||
displayName: 'Limit',
|
||||
description: 'Maximum number of leads to return',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { start_date, end_date, limit } = context.propsValue;
|
||||
|
||||
const queryParams: string[] = [];
|
||||
if (start_date) {
|
||||
const dateStr = new Date(start_date).toISOString().split('T')[0];
|
||||
queryParams.push(`start_date=${dateStr}`);
|
||||
}
|
||||
if (end_date) {
|
||||
const dateStr = new Date(end_date).toISOString().split('T')[0];
|
||||
queryParams.push(`end_date=${dateStr}`);
|
||||
}
|
||||
if (limit) {
|
||||
queryParams.push(`limit=${limit}`);
|
||||
}
|
||||
|
||||
const path = queryParams.length > 0
|
||||
? `/leads/?${queryParams.join('&')}`
|
||||
: '/leads/';
|
||||
|
||||
return await askHandleApiCall(
|
||||
context.auth.secret_text,
|
||||
HttpMethod.GET,
|
||||
path
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { createAction } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { askHandleAuth } from '../common/auth';
|
||||
import { askHandleApiCall } from '../common/client';
|
||||
|
||||
export const listRooms = createAction({
|
||||
auth: askHandleAuth,
|
||||
name: 'list_rooms',
|
||||
displayName: 'List Rooms',
|
||||
description: 'Get a list of all rooms',
|
||||
props: {},
|
||||
async run(context) {
|
||||
return await askHandleApiCall(
|
||||
context.auth.secret_text,
|
||||
HttpMethod.GET,
|
||||
'/rooms/'
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
import { PieceAuth } from '@activepieces/pieces-framework';
|
||||
|
||||
const BASE_URL = 'https://dashboard.askhandle.com/api/v1';
|
||||
|
||||
export const askHandleAuth = PieceAuth.SecretText({
|
||||
displayName: 'API Key',
|
||||
description: `
|
||||
To get your API Key:
|
||||
|
||||
1. Go to https://dashboard.askhandle.com
|
||||
2. Sign in to your account
|
||||
3. Navigate to API settings
|
||||
4. Create or copy your API token
|
||||
5. Paste it here
|
||||
`,
|
||||
required: true,
|
||||
validate: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'API key is required',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.GET,
|
||||
url: `${BASE_URL}/rooms/`,
|
||||
headers: {
|
||||
Authorization: `Token ${auth}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (response.status === 200) {
|
||||
return {
|
||||
valid: true,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Invalid API key',
|
||||
};
|
||||
} catch (error: any) {
|
||||
return {
|
||||
valid: false,
|
||||
error: 'Invalid API key. Please check your API key and try again.',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
|
||||
const BASE_URL = 'https://dashboard.askhandle.com/api/v1';
|
||||
|
||||
export async function askHandleApiCall(
|
||||
apiKey: string,
|
||||
method: HttpMethod,
|
||||
path: string,
|
||||
body?: unknown
|
||||
) {
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method,
|
||||
url: `${BASE_URL}${path}`,
|
||||
headers: {
|
||||
Authorization: `Token ${apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body,
|
||||
});
|
||||
|
||||
if (response.status >= 200 && response.status < 300) {
|
||||
return response.body;
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`AskHandle API error: ${response.status} ${JSON.stringify(response.body)}`
|
||||
);
|
||||
} catch (error: any) {
|
||||
const statusCode = error.response?.status;
|
||||
|
||||
if (statusCode) {
|
||||
switch (statusCode) {
|
||||
case 400:
|
||||
throw new Error(
|
||||
`Bad Request: Invalid request parameters. Please check your data.`
|
||||
);
|
||||
case 401:
|
||||
throw new Error(
|
||||
'Authentication Failed: Invalid API key. Please verify your AskHandle credentials.'
|
||||
);
|
||||
case 403:
|
||||
throw new Error(
|
||||
'Access Forbidden: You do not have permission to access this resource.'
|
||||
);
|
||||
case 404:
|
||||
throw new Error(
|
||||
'Resource Not Found: The requested resource does not exist.'
|
||||
);
|
||||
case 500:
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
throw new Error(
|
||||
`Server Error (${statusCode}): AskHandle API is experiencing issues. Please try again later.`
|
||||
);
|
||||
default:
|
||||
throw new Error(
|
||||
`AskHandle API Error (${statusCode}): ${error.message || 'Unknown error occurred'}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unexpected error: ${error.message || String(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
import { Property } from '@activepieces/pieces-framework';
|
||||
import { HttpMethod } from '@activepieces/pieces-common';
|
||||
import { askHandleApiCall } from './client';
|
||||
import { askHandleAuth } from './auth';
|
||||
|
||||
export const roomDropdown = Property.Dropdown({
|
||||
auth: askHandleAuth,
|
||||
displayName: 'Room',
|
||||
description: 'Select a room',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await askHandleApiCall(
|
||||
auth.secret_text,
|
||||
HttpMethod.GET,
|
||||
'/rooms/'
|
||||
);
|
||||
|
||||
const rooms = Array.isArray(response) ? response : (response)?.results || [];
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: rooms.map((room: any) => ({
|
||||
label: room.name || room.label || `Room ${room.uuid}`,
|
||||
value: room.uuid,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Error loading rooms',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const leadDropdown = Property.Dropdown({
|
||||
auth: askHandleAuth,
|
||||
displayName: 'Lead',
|
||||
description: 'Select a lead',
|
||||
required: true,
|
||||
refreshers: [],
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Please connect your account first',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await askHandleApiCall(
|
||||
auth.secret_text,
|
||||
HttpMethod.GET,
|
||||
'/leads/'
|
||||
);
|
||||
|
||||
const leads = Array.isArray(response) ? response : (response as any)?.results || [];
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
options: leads.map((lead: any) => ({
|
||||
label: lead.nickname || lead.email || `Lead ${lead.uuid}`,
|
||||
value: lead.uuid,
|
||||
})),
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
disabled: true,
|
||||
options: [],
|
||||
placeholder: 'Error loading leads',
|
||||
};
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
import { askHandleAuth } from '../common/auth';
|
||||
|
||||
const BASE_URL = 'https://dashboard.askhandle.com/api/v1';
|
||||
|
||||
export const newLeadTrigger = createTrigger({
|
||||
auth: askHandleAuth,
|
||||
name: 'new_lead',
|
||||
displayName: 'New Lead',
|
||||
description: 'Triggers when a new lead is created',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {},
|
||||
sampleData: {
|
||||
uuid: 'd8a2e337-9d4d-4515-979a-6f590379848f',
|
||||
nickname: 'John',
|
||||
email: 'john@example.com',
|
||||
phone_number: '+1234567890',
|
||||
device: 'Desktop',
|
||||
from_page_title: 'Homepage',
|
||||
referrer: 'https://example.com',
|
||||
created_at: '2021-09-15T12:08:50.676405Z',
|
||||
},
|
||||
async onEnable(context) {
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.POST,
|
||||
url: `${BASE_URL}/webhooks/`,
|
||||
headers: {
|
||||
Authorization: `Token ${context.auth}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
event: 'lead.added',
|
||||
target: context.webhookUrl,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.status === 200 || response.status === 201) {
|
||||
const webhook = response.body as { uuid: string };
|
||||
await context.store.put('_askhandle_webhook_lead', webhook.uuid);
|
||||
}
|
||||
} catch (error: any) {
|
||||
throw new Error(
|
||||
`Failed to enable webhook: ${error.message || String(error)}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable(context) {
|
||||
try {
|
||||
const webhookId = await context.store.get<string>(
|
||||
'_askhandle_webhook_lead'
|
||||
);
|
||||
|
||||
if (webhookId) {
|
||||
await httpClient.sendRequest({
|
||||
method: HttpMethod.DELETE,
|
||||
url: `${BASE_URL}/webhooks/${webhookId}/`,
|
||||
headers: {
|
||||
Authorization: `Token ${context.auth}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
await context.store.delete('_askhandle_webhook_lead');
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.warn('Failed to delete webhook during disable:', error);
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
const payload = context.payload.body as { data: any };
|
||||
return [payload.data || payload];
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
import { askHandleAuth } from '../common/auth';
|
||||
|
||||
const BASE_URL = 'https://dashboard.askhandle.com/api/v1';
|
||||
|
||||
export const newMessageTrigger = createTrigger({
|
||||
auth: askHandleAuth,
|
||||
name: 'new_message',
|
||||
displayName: 'New Message',
|
||||
description: 'Triggers when a new message is received',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {},
|
||||
sampleData: {
|
||||
uuid: 'ffb84155-5f12-4bee-bd50-3c868097e473',
|
||||
nickname: 'Mary',
|
||||
email: 'mary@example.com',
|
||||
body: 'Hello!',
|
||||
is_support_sender: false,
|
||||
sent_at: '2021-09-15T12:08:50.676405Z',
|
||||
},
|
||||
async onEnable(context) {
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.POST,
|
||||
url: `${BASE_URL}/webhooks/`,
|
||||
headers: {
|
||||
Authorization: `Token ${context.auth}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
event: 'message.added',
|
||||
target: context.webhookUrl,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.status === 200 || response.status === 201) {
|
||||
const webhook = response.body as { uuid: string };
|
||||
await context.store.put('_askhandle_webhook_message', webhook.uuid);
|
||||
}
|
||||
} catch (error: any) {
|
||||
throw new Error(
|
||||
`Failed to enable webhook: ${error.message || String(error)}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable(context) {
|
||||
try {
|
||||
const webhookId = await context.store.get<string>(
|
||||
'_askhandle_webhook_message'
|
||||
);
|
||||
|
||||
if (webhookId) {
|
||||
await httpClient.sendRequest({
|
||||
method: HttpMethod.DELETE,
|
||||
url: `${BASE_URL}/webhooks/${webhookId}/`,
|
||||
headers: {
|
||||
Authorization: `Token ${context.auth}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
await context.store.delete('_askhandle_webhook_message');
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.warn('Failed to delete webhook during disable:', error);
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
const payload = context.payload.body as { data: any };
|
||||
return [payload.data || payload];
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
createTrigger,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { HttpMethod, httpClient } from '@activepieces/pieces-common';
|
||||
import { askHandleAuth } from '../common/auth';
|
||||
|
||||
const BASE_URL = 'https://dashboard.askhandle.com/api/v1';
|
||||
|
||||
export const newRoomTrigger = createTrigger({
|
||||
auth: askHandleAuth,
|
||||
name: 'new_room',
|
||||
displayName: 'New Room',
|
||||
description: 'Triggers when a new room is created',
|
||||
type: TriggerStrategy.WEBHOOK,
|
||||
props: {},
|
||||
sampleData: {
|
||||
uuid: 'de1e39a5-a391-4d7f-836d-cf3589529af8',
|
||||
label: 'room-label-123',
|
||||
name: 'Customer Support Room',
|
||||
rating: 5,
|
||||
is_bot_use: false,
|
||||
created_at: '2021-09-15T12:08:50.676405Z',
|
||||
messages: [],
|
||||
},
|
||||
async onEnable(context) {
|
||||
try {
|
||||
const response = await httpClient.sendRequest({
|
||||
method: HttpMethod.POST,
|
||||
url: `${BASE_URL}/webhooks/`,
|
||||
headers: {
|
||||
Authorization: `Token ${context.auth}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: {
|
||||
event: 'chat.added',
|
||||
target: context.webhookUrl,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.status === 200 || response.status === 201) {
|
||||
const webhook = response.body as { uuid: string };
|
||||
await context.store.put('_askhandle_webhook_room', webhook.uuid);
|
||||
}
|
||||
} catch (error: any) {
|
||||
throw new Error(
|
||||
`Failed to enable webhook: ${error.message || String(error)}`
|
||||
);
|
||||
}
|
||||
},
|
||||
async onDisable(context) {
|
||||
try {
|
||||
const webhookId = await context.store.get<string>(
|
||||
'_askhandle_webhook_room'
|
||||
);
|
||||
|
||||
if (webhookId) {
|
||||
await httpClient.sendRequest({
|
||||
method: HttpMethod.DELETE,
|
||||
url: `${BASE_URL}/webhooks/${webhookId}/`,
|
||||
headers: {
|
||||
Authorization: `Token ${context.auth}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
await context.store.delete('_askhandle_webhook_room');
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.warn('Failed to delete webhook during disable:', error);
|
||||
}
|
||||
},
|
||||
async run(context) {
|
||||
const payload = context.payload.body as { data: any };
|
||||
return [payload.data || payload];
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user