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,94 @@
# Dittofeed Piece for ActivePieces
This piece provides integration with [Dittofeed](https://dittofeed.com/), a customer data platform for user analytics and tracking.
## Authentication
To use the Dittofeed piece, you need to provide:
1. **API Key**: Your Dittofeed API key for authentication
2. **Base URL**: The base URL of your Dittofeed instance (e.g., `https://api.dittofeed.com` or your self-hosted instance URL)
## Actions
### Identify User
Identify a user in Dittofeed with their unique ID and traits.
**Parameters:**
- **User ID** (required): A unique identifier for the user
- **User Traits** (optional): An object containing user properties like name, email, etc.
**Example:**
```json
{
"userId": "user123",
"traits": {
"name": "John Doe",
"email": "john@example.com",
"plan": "premium"
}
}
```
### Track Event
Track a user event in Dittofeed.
**Parameters:**
- **User ID** (required): A unique identifier for the user
- **Event** (required): The name of the event to track
- **Properties** (optional): An object containing event properties
**Example:**
```json
{
"userId": "user123",
"event": "purchase_completed",
"properties": {
"product": "Premium Plan",
"price": 99.99,
"currency": "USD"
}
}
```
### Screen View
Track a screen view event in Dittofeed.
**Parameters:**
- **User ID** (required): A unique identifier for the user
- **Name** (required): The name of the screen viewed
- **Properties** (optional): An object containing screen view properties
**Example:**
```json
{
"userId": "user123",
"name": "checkout_page",
"properties": {
"referrer": "product_page",
"device": "mobile"
}
}
```
## Troubleshooting
### Common Errors
1. **Authentication failed**: Check that your API key is correct and has the necessary permissions.
2. **API endpoint not found**: Verify that your base URL is correct and points to a valid Dittofeed instance.
3. **Rate limit exceeded**: You've made too many requests in a short period. Wait and try again later.
4. **Invalid input**: Ensure that your User ID is not empty and that traits/properties are valid objects.
### Best Practices
1. Use consistent User IDs across all actions to ensure proper user tracking.
2. Keep event names consistent and descriptive for better analytics.
3. Include relevant properties with events and screen views to capture valuable context.
## Building
Run `nx build pieces-dittofeed` to build the library.

View File

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

View File

@@ -0,0 +1,65 @@
{
"name": "pieces-dittofeed",
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/pieces/community/dittofeed/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/dittofeed",
"tsConfig": "packages/pieces/community/dittofeed/tsconfig.lib.json",
"packageJson": "packages/pieces/community/dittofeed/package.json",
"main": "packages/pieces/community/dittofeed/src/index.ts",
"assets": [
"packages/pieces/community/dittofeed/*.md",
{
"input": "packages/pieces/community/dittofeed/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/dittofeed",
"command": "bun install --no-save --silent"
},
"dependsOn": [
"^build"
]
}
}
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Kundendatenplattform für Benutzeranalyse und -verfolgung",
"API Key": "API-Schlüssel",
"Base URL": "Basis-URL",
"Your API key of Dittofeed.": "Ihr API-Schlüssel des Dittofeed.",
"The base URL of your Dittofeed instance.": "Die Basis-URL deiner Dittofeed-Instanz.",
"Identify User": "Benutzer identifizieren",
"Track Event": "Ereignis verfolgen",
"Screen Event": "Bildschirmereignis",
"Identify a user in Dittofeed.": "Benutzer im Dittofeed identifizieren.",
"Track an event for a user.": "Verfolgen Sie ein Ereignis für einen Benutzer.",
"Track a screen view event.": "Verfolgen Sie eine Bildschirmansicht.",
"User ID": "Benutzer-ID",
"User Traits": "Benutzereigenschaften",
"Event Name": "Ereignisname",
"Event Properties": "Ereigniseigenschaften",
"Screen Name": "Bildschirmname",
"Screen Properties": "Bildschirmeigenschaften"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Plataforma de datos de clientes para análisis y seguimiento de usuarios",
"API Key": "Clave API",
"Base URL": "URL base",
"Your API key of Dittofeed.": "Tu clave API de Dittofeed.",
"The base URL of your Dittofeed instance.": "La URL base de tu instancia de Dittofeed.",
"Identify User": "Identificar usuario",
"Track Event": "Rastrear evento",
"Screen Event": "Evento de pantalla",
"Identify a user in Dittofeed.": "Identificar un usuario en Dittofeed.",
"Track an event for a user.": "Rastrear un evento para un usuario.",
"Track a screen view event.": "Rastrear un evento de vista de pantalla.",
"User ID": "ID Usuario",
"User Traits": "Rasgos de usuario",
"Event Name": "Nombre del evento",
"Event Properties": "Propiedades del evento",
"Screen Name": "Nombre de usuario",
"Screen Properties": "Propiedades de pantalla"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Plateforme de données client pour l'analyse et le suivi des utilisateurs",
"API Key": "Clé API",
"Base URL": "URL de base",
"Your API key of Dittofeed.": "Votre clé API de Dittofeed.",
"The base URL of your Dittofeed instance.": "L'URL de base de votre instance Dittofeed.",
"Identify User": "Identifier l'utilisateur",
"Track Event": "Suivre l'évènement",
"Screen Event": "Evénement de l'écran",
"Identify a user in Dittofeed.": "Identifier un utilisateur dans Dittofeed.",
"Track an event for a user.": "Suivre un événement pour un utilisateur.",
"Track a screen view event.": "Suivre un événement en vue d'écran.",
"User ID": "Identifiant de l'utilisateur",
"User Traits": "Caractéristiques de l'utilisateur",
"Event Name": "Nom de l'événement",
"Event Properties": "Propriétés de l'événement",
"Screen Name": "Nom d'écran",
"Screen Properties": "Propriétés de l'écran"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "ユーザー分析と追跡のための顧客データプラットフォーム",
"API Key": "API キー",
"Base URL": "ベースURL",
"Your API key of Dittofeed.": "ディットフィードの API キー。",
"The base URL of your Dittofeed instance.": "DittofeedインスタンスのベースURL。",
"Identify User": "ユーザーを識別する",
"Track Event": "イベントを追跡",
"Screen Event": "スクリーンイベント",
"Identify a user in Dittofeed.": "Dittofeedでユーザーを識別します。",
"Track an event for a user.": "ユーザーのイベントを追跡します。",
"Track a screen view event.": "画面表示イベントを追跡します。",
"User ID": "ユーザー ID",
"User Traits": "ユーザーの特性",
"Event Name": "イベント名",
"Event Properties": "イベントのプロパティ",
"Screen Name": "画面名",
"Screen Properties": "画面のプロパティ"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Platform voor klantgegevens voor gebruikersanalyses en het volgen van gegevens",
"API Key": "API Sleutel",
"Base URL": "Basis URL",
"Your API key of Dittofeed.": "Je API-sleutel van Dittofeed.",
"The base URL of your Dittofeed instance.": "De basis-URL van je Dittofeed instantie.",
"Identify User": "Identificeer gebruiker",
"Track Event": "Volg Evenement",
"Screen Event": "Scherm Evenement",
"Identify a user in Dittofeed.": "Identificeer een gebruiker in Dittofeed.",
"Track an event for a user.": "Volg een gebeurtenis voor een gebruiker.",
"Track a screen view event.": "Houd een schermweergave gebeurtenis bij.",
"User ID": "Gebruiker ID",
"User Traits": "Gebruiker Eigenschappen",
"Event Name": "Naam van gebeurtenis",
"Event Properties": "Evenement eigenschappen",
"Screen Name": "Schermnaam",
"Screen Properties": "Scherm Eigenschappen"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Plataforma de dados do cliente para análise e rastreamento do usuário",
"API Key": "Chave de API",
"Base URL": "URL Base",
"Your API key of Dittofeed.": "Sua chave da API do Dittofeed.",
"The base URL of your Dittofeed instance.": "A URL base da instância do Dittofeed",
"Identify User": "Identificar Usuário",
"Track Event": "Rastrear evento",
"Screen Event": "Evento Tela",
"Identify a user in Dittofeed.": "Identificar um usuário em Dittofeed.",
"Track an event for a user.": "Acompanha um evento para um usuário.",
"Track a screen view event.": "Rastrear um evento de visualização de tela.",
"User ID": "ID de usuário",
"User Traits": "Características do Usuário",
"Event Name": "Nome do Evento",
"Event Properties": "Propriedades do evento",
"Screen Name": "Nome de exibição",
"Screen Properties": "Propriedades da tela"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Customer data platform for user analytics and tracking",
"API Key": "API Key",
"Base URL": "Base URL",
"Your API key of Dittofeed.": "Your API key of Dittofeed.",
"The base URL of your Dittofeed instance.": "The base URL of your Dittofeed instance.",
"Identify User": "Identify User",
"Track Event": "Track Event",
"Screen Event": "Screen Event",
"Identify a user in Dittofeed.": "Identify a user in Dittofeed.",
"Track an event for a user.": "Track an event for a user.",
"Track a screen view event.": "Track a screen view event.",
"User ID": "User ID",
"User Traits": "User Traits",
"Event Name": "Event Name",
"Event Properties": "Event Properties",
"Screen Name": "Screen Name",
"Screen Properties": "Screen Properties"
}

View File

@@ -0,0 +1,19 @@
{
"Customer data platform for user analytics and tracking": "Customer data platform for user analytics and tracking",
"API Key": "API 密钥",
"Base URL": "基本网址",
"Your API key of Dittofeed.": "Your API key of Dittofeed.",
"The base URL of your Dittofeed instance.": "The base URL of your Dittofeed instance.",
"Identify User": "Identify User",
"Track Event": "Track Event",
"Screen Event": "Screen Event",
"Identify a user in Dittofeed.": "Identify a user in Dittofeed.",
"Track an event for a user.": "Track an event for a user.",
"Track a screen view event.": "Track a screen view event.",
"User ID": "User ID",
"User Traits": "User Traits",
"Event Name": "Event Name",
"Event Properties": "Event Properties",
"Screen Name": "Screen Name",
"Screen Properties": "Screen Properties"
}

View File

@@ -0,0 +1,41 @@
import { createPiece, PieceAuth, Property } from "@activepieces/pieces-framework";
import { PieceCategory } from "@activepieces/shared";
import { identifyAction } from './lib/actions/identify';
import { trackAction } from './lib/actions/track';
import { screenAction } from './lib/actions/screen';
export const dittofeedAuth = PieceAuth.CustomAuth({
props: {
apiKey: PieceAuth.SecretText({
displayName: 'API Key',
required: true,
description: 'Your API key of Dittofeed.',
}),
baseUrl: Property.ShortText({
displayName: 'Base URL',
required: true,
description: 'The base URL of your Dittofeed instance.',
defaultValue: 'http://localhost:3200',
}),
},
required: true,
});
export const dittofeed = createPiece({
displayName: "Dittofeed",
auth: dittofeedAuth,
minimumSupportedRelease: '0.36.1',
logoUrl: "https://cdn.activepieces.com/pieces/dittofeed.png",
authors: [
'SmarterService'
],
categories: [
PieceCategory.MARKETING,
PieceCategory.BUSINESS_INTELLIGENCE
],
description: 'Customer data platform for user analytics and tracking',
actions: [identifyAction, trackAction, screenAction],
triggers: [],
});

View File

@@ -0,0 +1,53 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { dittofeedAuth } from '../..';
export const identifyAction = createAction({
name: 'identify',
auth: dittofeedAuth,
displayName: 'Identify User',
description: 'Identify a user in Dittofeed.',
props: {
userId: Property.ShortText({
displayName: 'User ID',
required: true,
}),
traits: Property.Object({
displayName: 'User Traits',
required: false,
}),
},
async run(context) {
const { userId, traits } = context.propsValue;
const { apiKey, baseUrl } = context.auth.props;
try {
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${baseUrl}/api/public/apps/identify`,
headers: {
Authorization: apiKey,
},
body: {
type: 'identify',
messageId: `identify-${userId}-${Date.now()}`,
userId,
traits,
},
});
return response.body;
} catch (error: any) {
if (error.response?.status === 401) {
throw new Error('Authentication failed. Please check your API key.');
} else if (error.response?.status === 404) {
throw new Error(`Dittofeed API endpoint not found. Please check your base URL: ${baseUrl}`);
} else if (error.response?.status === 429) {
throw new Error('Rate limit exceeded. Please try again later.');
} else if (error.response?.status >= 500) {
throw new Error(`Dittofeed server error: ${error.response?.body?.message || error.message}`);
}
throw new Error(`Failed to identify user in Dittofeed: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,58 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { dittofeedAuth } from '../..';
export const screenAction = createAction({
name: 'screen',
auth: dittofeedAuth,
displayName: 'Screen Event',
description: 'Track a screen view event.',
props: {
userId: Property.ShortText({
displayName: 'User ID',
required: true,
}),
name: Property.ShortText({
displayName: 'Screen Name',
required: true,
}),
properties: Property.Object({
displayName: 'Screen Properties',
required: false,
}),
},
async run(context) {
const { userId, name, properties } = context.propsValue;
const { apiKey, baseUrl } = context.auth.props;
try {
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${baseUrl}/api/public/apps/screen`,
headers: {
Authorization: apiKey,
},
body: {
type: 'screen',
messageId: `screen-${userId}-${name}-${Date.now()}`,
userId,
name,
properties,
},
});
return response.body;
} catch (error: any) {
if (error.response?.status === 401) {
throw new Error('Authentication failed. Please check your API key.');
} else if (error.response?.status === 404) {
throw new Error(`Dittofeed API endpoint not found. Please check your base URL: ${baseUrl}`);
} else if (error.response?.status === 429) {
throw new Error('Rate limit exceeded. Please try again later.');
} else if (error.response?.status >= 500) {
throw new Error(`Dittofeed server error: ${error.response?.body?.message || error.message}`);
}
throw new Error(`Failed to track screen view in Dittofeed: ${error.message || 'Unknown error'}`);
}
},
});

View File

@@ -0,0 +1,58 @@
import { createAction, Property } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { dittofeedAuth } from '../..';
export const trackAction = createAction({
name: 'track',
auth: dittofeedAuth,
displayName: 'Track Event',
description: 'Track an event for a user.',
props: {
userId: Property.ShortText({
displayName: 'User ID',
required: true,
}),
event: Property.ShortText({
displayName: 'Event Name',
required: true,
}),
properties: Property.Object({
displayName: 'Event Properties',
required: false,
}),
},
async run(context) {
const { userId, event, properties } = context.propsValue;
const { apiKey, baseUrl } = context.auth.props;
try {
const response = await httpClient.sendRequest({
method: HttpMethod.POST,
url: `${baseUrl}/api/public/apps/track`,
headers: {
Authorization: apiKey,
},
body: {
type: 'track',
messageId: `track-${userId}-${event}-${Date.now()}`,
userId,
event,
properties,
},
});
return response.body;
} catch (error: any) {
if (error.response?.status === 401) {
throw new Error('Authentication failed. Please check your API key.');
} else if (error.response?.status === 404) {
throw new Error(`Dittofeed API endpoint not found. Please check your base URL: ${baseUrl}`);
} else if (error.response?.status === 429) {
throw new Error('Rate limit exceeded. Please try again later.');
} else if (error.response?.status >= 500) {
throw new Error(`Dittofeed server error: ${error.response?.body?.message || error.message}`);
}
throw new Error(`Failed to track event in Dittofeed: ${error.message || 'Unknown 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"]
}