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,35 @@
import { PieceAuth } from '@activepieces/pieces-framework';
import { httpClient, HttpMethod } from '@activepieces/pieces-common';
import { uscreenPublisherApiUrl } from './client';
export const uscreenAuth = PieceAuth.SecretText({
displayName: 'API Key',
description: `
To get your API key:
1. Log in to your Uscreen account
2. Contact your Customer Success Manager to have an API key (X-Store-Token) issued.
`,
required: true,
validate: async ({ auth }) => {
try {
await httpClient.sendRequest({
method: HttpMethod.GET,
url: `${uscreenPublisherApiUrl}/offers`,
headers: {
'X-Store-Token': auth,
'Accept': 'application/json'
}
});
return {
valid: true,
};
} catch (e) {
return {
valid: false,
error: 'Invalid API key or insufficient permissions.',
};
}
},
});

View File

@@ -0,0 +1,125 @@
import { httpClient, HttpMethod, HttpRequest, QueryParams } from "@activepieces/pieces-common";
export const uscreenApiUrl = 'https://api.uscreen.io/v1';
export const uscreenPublisherApiUrl = 'https://uscreen.io/publisher_api/v1';
export interface UscreenProduct {
id: number;
name: string;
}
export interface UscreenInvoice {
id: string;
title: string;
total: string;
amount: string;
discount: string;
offer_id: string;
customer_name: string;
customer_email: string;
status: string;
paid_at: string;
created_at: string;
[key: string]: unknown;
}
export class UscreenClient {
constructor(private apiKey: string) {}
/**
* Makes an authenticated request to the Uscreen PUBLISHER API.
*/
async makeRequest<T>(method: HttpMethod, url: string, body?: object, query?: QueryParams): Promise<T> {
const request: HttpRequest<object> = {
method,
url: `${uscreenPublisherApiUrl}${url}`,
body: body,
queryParams: query,
headers: {
"X-Store-Token": this.apiKey,
"Accept": "application/json",
"Content-Type": "application/json",
},
};
const { body: responseBody } = await httpClient.sendRequest<T>(request);
return responseBody;
}
/**
* Fetches a paginated list of invoices, sorted by payment date.
*/
async getInvoices(params: {
sort_by: string,
status: string,
per_page?: number
}): Promise<{ items: UscreenInvoice[] }> {
const query: QueryParams = {
sort_by: params.sort_by,
status: params.status,
};
if (params.per_page !== undefined) {
query['per_page'] = params.per_page.toString();
}
try {
return await this.makeRequest<{ items: UscreenInvoice[] }>(
HttpMethod.GET,
'/invoices',
undefined,
query
);
} catch (e) {
console.error("Failed to fetch Uscreen invoices", e);
return { items: [] };
}
}
/**
* Fetches a list of offers (subscriptions).
*/
async getOffers(): Promise<UscreenProduct[]> {
try {
return await this.makeRequest<UscreenProduct[]>(
HttpMethod.GET,
'/offers'
);
} catch (e) {
console.error("Failed to fetch Uscreen offers", e);
return [];
}
}
/**
* Fetches a list of programs (bundles).
*/
async getPrograms(): Promise<UscreenProduct[]> {
try {
return await this.makeRequest<UscreenProduct[]>(
HttpMethod.GET,
'/programs'
);
} catch (e) {
console.error("Failed to fetch Uscreen programs", e);
return [];
}
}
async getCustomers() {
try {
return await this.makeRequest<{ id: number; email: string }[]>(
HttpMethod.GET,
'/customers'
);
} catch (e) {
console.error("Failed to fetch Uscreen customers", e);
return [];
}
}
}

View File

@@ -0,0 +1,116 @@
import { Property } from '@activepieces/pieces-framework';
import { UscreenClient, UscreenProduct } from './client';
import { uscreenAuth } from './auth';
export const uscreenProps = {
customerId: (required = true) =>
Property.Dropdown({
auth: uscreenAuth,
displayName: 'Customer ID or Email',
description: 'The unique ID or email address of the customer.',
required: required,
refreshers: ['productType'],
options: async (context) => {
const auth = context['auth'];
if (!auth) {
return {
disabled: true,
placeholder: 'Connect your account first',
options: [],
};
}
const client = new UscreenClient(auth.secret_text);
const customers = await client.getCustomers();
return {
disabled: false,
options: customers.map((customer) => ({
label: customer.email,
value: customer.id,
})),
};
},
}),
productType: (required = true) =>
Property.StaticDropdown({
displayName: 'Product Type',
description: 'The type of product to assign.',
required: required,
options: {
options: [
{ label: 'Program (Bundle)', value: 'program' },
{ label: 'Offer (Subscription)', value: 'offer' },
],
},
}),
productId: (required = true) =>
Property.Dropdown({
auth: uscreenAuth,
displayName: 'Product',
description: 'The bundle (program) or subscription (offer) to assign.',
required: required,
refreshers: ['productType'],
options: async (context) => {
const auth = context['auth'];
const propsValue = context['propsValue'] as Record<string, unknown>;
const productType = propsValue['productType'] as
| 'program'
| 'offer'
| undefined;
if (!auth) {
return {
disabled: true,
placeholder: 'Connect your account first',
options: [],
};
}
if (!productType) {
return {
disabled: true,
placeholder: 'Select a Product Type first',
options: [],
};
}
const client = new UscreenClient(auth.secret_text);
let products: UscreenProduct[] = [];
if (productType === 'program') {
products = await client.getPrograms();
} else if (productType === 'offer') {
products = await client.getOffers();
}
return {
disabled: false,
options: products.map((product) => ({
label: product.name,
value: product.id,
})),
};
},
}),
webhookInstructions: (required = true) =>
Property.MarkDown({
value: `## Setup Instructions
### 1. Access Uscreen Webhook Settings
- Log into your **Uscreen Admin Panel**
- Navigate to **Settings** > **Webhooks**
### 2. Create New Webhook
- Click **"New Webhook"**
- **Callback URL**:
\`\`\`text
{{webhookUrl}}
\`\`\`
- Select the appropriate event
- Click **Save**`,
}),
};