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 @@
export * from './lib';

View File

@@ -0,0 +1,81 @@
import { Static, Type } from '@sinclair/typebox';
import { ActionContext } from '../context';
import { ActionBase } from '../piece-metadata';
import { InputPropertyMap } from '../property';
import { ExtractPieceAuthPropertyTypeForMethods, PieceAuthProperty } from '../property/authentication';
export type ActionRunner<PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = PieceAuthProperty, ActionProps extends InputPropertyMap = InputPropertyMap> =
(ctx: ActionContext<PieceAuth, ActionProps>) => Promise<unknown | void>
export const ErrorHandlingOptionsParam = Type.Object({
retryOnFailure: Type.Object({
defaultValue: Type.Optional(Type.Boolean()),
hide: Type.Optional(Type.Boolean()),
}),
continueOnFailure: Type.Object({
defaultValue: Type.Optional(Type.Boolean()),
hide: Type.Optional(Type.Boolean()),
}),
})
export type ErrorHandlingOptionsParam = Static<typeof ErrorHandlingOptionsParam>
type CreateActionParams<PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined, ActionProps extends InputPropertyMap> = {
/**
* A dummy parameter used to infer {@code PieceAuth} type
*/
name: string
/**
* this parameter is used to infer the type of the piece auth value in run and test methods
*/
auth?: PieceAuth
displayName: string
description: string
props: ActionProps
run: ActionRunner<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, ActionProps>
test?: ActionRunner<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, ActionProps>
requireAuth?: boolean
errorHandlingOptions?: ErrorHandlingOptionsParam
}
export class IAction<PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = any, ActionProps extends InputPropertyMap = InputPropertyMap> implements ActionBase {
constructor(
public readonly name: string,
public readonly displayName: string,
public readonly description: string,
public readonly props: ActionProps,
public readonly run: ActionRunner<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, ActionProps>,
public readonly test: ActionRunner<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, ActionProps>,
public readonly requireAuth: boolean,
public readonly errorHandlingOptions: ErrorHandlingOptionsParam,
) { }
}
export type Action<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = any,
ActionProps extends InputPropertyMap = any,
> = IAction<PieceAuth, ActionProps>
export const createAction = <
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = PieceAuthProperty,
ActionProps extends InputPropertyMap = any
>(
params: CreateActionParams<PieceAuth, ActionProps>,
) => {
return new IAction(
params.name,
params.displayName,
params.description,
params.props,
params.run,
params.test ?? params.run,
params.requireAuth ?? true,
params.errorHandlingOptions ?? {
continueOnFailure: {
defaultValue: false,
},
retryOnFailure: {
defaultValue: false,
}
},
)
}

View File

@@ -0,0 +1,273 @@
import {
AgentTool,
AppConnectionType,
AppConnectionValue,
ExecutionType,
FlowRunId,
PopulatedFlow,
ProjectId,
RespondResponse,
ResumePayload,
SeekPage,
TriggerPayload,
TriggerStrategy,
} from '@activepieces/shared';
import {
BasicAuthProperty,
CustomAuthProperty,
InputPropertyMap,
OAuth2Property,
SecretTextProperty,
StaticPropsValue,
} from '../property';
import { PieceAuthProperty } from '../property/authentication';
import { DelayPauseMetadata, PauseMetadata, WebhookPauseMetadata } from '@activepieces/shared';
export type BaseContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
Props extends InputPropertyMap
> = {
flows: FlowsContext;
step: StepContext;
auth: AppConnectionValueForAuthProperty<PieceAuth>;
propsValue: StaticPropsValue<Props>;
store: Store;
project: {
id: ProjectId;
externalId: () => Promise<string | undefined>;
};
connections: ConnectionsManager;
};
type ExtractCustomAuthProps<T> = T extends CustomAuthProperty<infer Props> ? Props : never;
type ExtractOAuth2Props<T> = T extends OAuth2Property<infer Props> ? Props : never;
export type AppConnectionValueForAuthProperty<T extends PieceAuthProperty | PieceAuthProperty[] | undefined> =
T extends PieceAuthProperty[] ? AppConnectionValueForSingleAuthProperty<T[number]> :
T extends PieceAuthProperty ? AppConnectionValueForSingleAuthProperty<T> :
T extends undefined ? undefined : never;
type AppConnectionValueForSingleAuthProperty<T extends PieceAuthProperty | undefined> =
T extends SecretTextProperty<boolean> ? AppConnectionValue<AppConnectionType.SECRET_TEXT> :
T extends BasicAuthProperty ? AppConnectionValue<AppConnectionType.BASIC_AUTH> :
T extends CustomAuthProperty<any> ? AppConnectionValue<AppConnectionType.CUSTOM_AUTH, StaticPropsValue<ExtractCustomAuthProps<T>>> :
T extends OAuth2Property<any> ? AppConnectionValue<AppConnectionType.OAUTH2, StaticPropsValue<ExtractOAuth2Props<T>>> :
T extends undefined ? undefined : never;
type AppWebhookTriggerHookContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap
> = BaseContext<PieceAuth, TriggerProps> & {
webhookUrl: string;
payload: TriggerPayload;
app: {
createListeners({
events,
identifierValue,
}: {
events: string[];
identifierValue: string;
}): void;
};
};
type PollingTriggerHookContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap
> = BaseContext<PieceAuth, TriggerProps> & {
setSchedule(schedule: { cronExpression: string; timezone?: string }): void;
};
type WebhookTriggerHookContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap,
> = BaseContext<PieceAuth, TriggerProps> & {
webhookUrl: string;
payload: TriggerPayload;
server: ServerContext;
};
export type TriggerHookContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap,
S extends TriggerStrategy,
> = S extends TriggerStrategy.APP_WEBHOOK
? AppWebhookTriggerHookContext<PieceAuth, TriggerProps>
: S extends TriggerStrategy.POLLING
? PollingTriggerHookContext<PieceAuth, TriggerProps>
: S extends TriggerStrategy.WEBHOOK
? WebhookTriggerHookContext<PieceAuth, TriggerProps> & {
server: ServerContext;
}
: never;
export type TestOrRunHookContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap,
S extends TriggerStrategy
> = TriggerHookContext<PieceAuth, TriggerProps, S> & {
files: FilesService;
};
export type StopHookParams = {
response: RespondResponse;
};
export type RespondHookParams = {
response: RespondResponse;
};
export type StopHook = (params?: StopHookParams) => void;
export type RespondHook = (params?: RespondHookParams) => void;
export type PauseHookParams = {
pauseMetadata: PauseMetadata;
};
export type PauseHook = (params: {
pauseMetadata: Omit<DelayPauseMetadata, 'requestIdToReply'> | Omit<WebhookPauseMetadata, 'requestId' | 'requestIdToReply'>
}) => void;
export type FlowsContext = {
list(params?: ListFlowsContextParams): Promise<SeekPage<PopulatedFlow>>
current: {
id: string;
version: {
id: string;
};
};
}
export type StepContext = {
name: string;
}
export type ListFlowsContextParams = {
externalIds?: string[]
}
export type PropertyContext = {
server: ServerContext;
project: {
id: ProjectId;
externalId: () => Promise<string | undefined>;
};
searchValue?: string;
flows: FlowsContext;
connections: ConnectionsManager;
};
export type ServerContext = {
apiUrl: string;
publicUrl: string;
token: string;
};
export type RunContext = {
id: FlowRunId;
stop: StopHook;
pause: PauseHook;
respond: RespondHook;
}
export type OnStartContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap
> = Omit<BaseContext<PieceAuth, TriggerProps>, 'flows'> & {
run: Pick<RunContext, 'id'>;
payload: unknown;
}
export type OutputContext = {
update: (params: {
data: {
[key: string]: unknown;
};
}) => Promise<void>;
}
type BaseActionContext<
ET extends ExecutionType,
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
ActionProps extends InputPropertyMap
> = BaseContext<PieceAuth, ActionProps> & {
executionType: ET;
tags: TagsManager;
server: ServerContext;
files: FilesService;
output: OutputContext;
agent: AgentContext;
run: RunContext;
generateResumeUrl: (params: {
queryParams: Record<string, string>,
sync?: boolean
}) => string;
};
type BeginExecutionActionContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined,
ActionProps extends InputPropertyMap = InputPropertyMap
> = BaseActionContext<ExecutionType.BEGIN, PieceAuth, ActionProps>;
type ResumeExecutionActionContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined,
ActionProps extends InputPropertyMap = InputPropertyMap
> = BaseActionContext<ExecutionType.RESUME, PieceAuth, ActionProps> & {
resumePayload: ResumePayload;
};
export type ActionContext<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined,
ActionProps extends InputPropertyMap = InputPropertyMap
> =
| BeginExecutionActionContext<PieceAuth, ActionProps>
| ResumeExecutionActionContext<PieceAuth, ActionProps>;
export type ConstructToolParams = {
tools: AgentTool[]
model: unknown,
}
export interface AgentContext {
tools: (params: ConstructToolParams) => Promise<Record<string, unknown>>;
}
export interface FilesService {
write({
fileName,
data,
}: {
fileName: string;
data: Buffer;
}): Promise<string>;
}
export interface ConnectionsManager {
get(
key: string
): Promise<AppConnectionValue | Record<string, unknown> | string | null>;
}
export interface TagsManager {
add(params: { name: string }): Promise<void>;
}
export interface Store {
put<T>(key: string, value: T, scope?: StoreScope): Promise<T>;
get<T>(key: string, scope?: StoreScope): Promise<T | null>;
delete(key: string, scope?: StoreScope): Promise<void>;
}
export enum StoreScope {
// Collection were deprecated in favor of project
PROJECT = 'COLLECTION',
FLOW = 'FLOW',
}

View File

@@ -0,0 +1,33 @@
import { ActionContext } from ".";
import { InputPropertyMap, PieceAuthProperty } from "../property";
export enum ContextVersion {
V1 = '1'
}
//bump these two constants after creating a new context version
export const LATEST_CONTEXT_VERSION = ContextVersion.V1;
export const MINIMUM_SUPPORTED_RELEASE_AFTER_LATEST_CONTEXT_VERSION = '0.73.0';
export const backwardCompatabilityContextUtils = {
makeActionContextBackwardCompatible({ context, contextVersion }: MakeActionContextBackwardCompatibleParams): ActionContext<PieceAuthProperty,InputPropertyMap> {
switch (contextVersion) {
case undefined:
return migrateActionContextV1ToV0(context);
case ContextVersion.V1:
return context;
}
}
}
function migrateActionContextV1ToV0(context: ActionContext<PieceAuthProperty,InputPropertyMap>): ActionContext<PieceAuthProperty,InputPropertyMap> {
return {
...context,
serverUrl: context.server.publicUrl,
} as unknown as ActionContext<PieceAuthProperty,InputPropertyMap>
}
type MakeActionContextBackwardCompatibleParams = {
context: ActionContext<PieceAuthProperty,InputPropertyMap>;
contextVersion: ContextVersion | undefined;
}

View File

@@ -0,0 +1,124 @@
import { I18nForPiece, PieceMetadataModel, PieceMetadataModelSummary } from "./piece-metadata"
import { LocalesEnum, MAX_KEY_LENGTH_FOR_CORWDIN } from "@activepieces/shared"
import path from 'path';
import fs from 'fs/promises';
export const pieceTranslation = {
translatePiece: <T extends PieceMetadataModelSummary | PieceMetadataModel>(piece: T, locale?: LocalesEnum): T => {
if (!locale) {
return piece
}
try {
const target = piece.i18n?.[locale]
if (!target) {
return piece
}
const translatedPiece: T = JSON.parse(JSON.stringify(piece))
pieceTranslation.pathsToValuesToTranslate.forEach(key => {
translateProperty(translatedPiece, key, target)
})
return translatedPiece
}
catch (err) {
console.error(`error translating piece ${piece.name}:`, err)
return piece
}
},
/**Gets the piece metadata regardles of piece location (node_modules or dist), wasn't included inside piece.metadata() for backwards compatibility issues (if an old ap version installs a new piece it would fail)*/
initializeI18n: async (pieceOutputPath: string): Promise<I18nForPiece | undefined> => {
try {
const locales = Object.values(LocalesEnum);
const i18n: I18nForPiece = {};
for (const locale of locales) {
const translations = await readLocaleFile(locale, pieceOutputPath);
if (translations) {
i18n[locale] = translations;
}
}
return Object.keys(i18n).length > 0 ? i18n : undefined;
}
catch (err) {
console.log(`Error initializing i18n for ${pieceOutputPath}:`, err)
return undefined
}
},
pathsToValuesToTranslate: [
"description",
"auth.username.displayName",
"auth.username.description",
"auth.password.displayName",
"auth.password.description",
"auth.props.*.displayName",
"auth.props.*.description",
"auth.props.*.options.options.*.label",
"auth.description",
"actions.*.displayName",
"actions.*.description",
"actions.*.props.*.displayName",
"actions.*.props.*.description",
"actions.*.props.*.options.options.*.label",
"triggers.*.displayName",
"triggers.*.description",
"triggers.*.props.*.displayName",
"triggers.*.props.*.description",
"triggers.*.props.*.options.options.*.label"
]
}
/**This function translates a property inside a piece, i.e description, displayName, etc...
*
* @param pieceModelOrProperty - The piece model or property to translate
* @param path - The path to the property to translate, i.e auth.username.displayName
* @param i18n - The i18n object
*/
function translateProperty(pieceModelOrProperty: Record<string, unknown>, path: string, i18n: Record<string, string>) {
const parsedKeys = path.split('.');
if (parsedKeys[0] === '*') {
return Object.values(pieceModelOrProperty).forEach(item => translateProperty(item as Record<string, unknown>, parsedKeys.slice(1).join('.'), i18n))
}
const nextObject = pieceModelOrProperty[parsedKeys[0]] as Record<string, unknown>;
if (!nextObject) {
return;
}
if (parsedKeys.length > 1) {
return translateProperty(nextObject, parsedKeys.slice(1).join('.'), i18n);
}
const propertyValue = pieceModelOrProperty[parsedKeys[0]] as string
const valueInI18n = i18n[propertyValue.slice(0, MAX_KEY_LENGTH_FOR_CORWDIN)]
if (valueInI18n) {
pieceModelOrProperty[parsedKeys[0]] = valueInI18n
}
}
async function fileExists(filePath: string) {
try {
await fs.access(filePath);
return true;
} catch {
return false;
}
}
const readLocaleFile = async (locale: LocalesEnum, pieceOutputPath: string) => {
const filePath = path.join(pieceOutputPath, 'src', 'i18n', `${locale}.json`);
if (!(await fileExists(filePath))) {
return null;
}
try {
const fileContent = await fs.readFile(filePath, 'utf8');
const translations = JSON.parse(fileContent);
if (typeof translations === 'object' && translations !== null) {
return translations;
}
throw new Error(`Invalid i18n file format for ${locale} in piece ${pieceOutputPath}`);
} catch (error) {
console.error(`Error reading i18n file for ${locale} in piece ${pieceOutputPath}:`, error);
return null;
}
}

View File

@@ -0,0 +1,8 @@
export * from './action/action';
export * from './property';
export * from './trigger/trigger';
export * from './context';
export * from './piece';
export * from './piece-metadata';
export * from './i18n'
export * from './context/versioning'

View File

@@ -0,0 +1,144 @@
import { PiecePropertyMap } from "./property";
import { WebhookRenewConfiguration } from "./trigger/trigger";
import { ErrorHandlingOptionsParam } from "./action/action";
import { PieceAuthProperty } from "./property/authentication";
import { Static, Type } from "@sinclair/typebox";
import { LocalesEnum, PackageType, PieceCategory, PieceType, ProjectId, TriggerStrategy, TriggerTestStrategy, WebhookHandshakeConfiguration } from "@activepieces/shared";
import { ContextVersion } from "./context/versioning";
const I18nForPiece = Type.Optional(Type.Partial(Type.Record(Type.Enum(LocalesEnum), Type.Record(Type.String(), Type.String()))));
export type I18nForPiece = Static<typeof I18nForPiece>
export const PieceBase = Type.Object({
id: Type.Optional(Type.String()),
name: Type.String(),
displayName: Type.String(),
logoUrl: Type.String(),
description: Type.String(),
projectId: Type.Optional(Type.String()),
authors: Type.Array(Type.String()),
platformId: Type.Optional(Type.String()),
directoryPath: Type.Optional(Type.String()),
auth: Type.Optional(Type.Union([PieceAuthProperty, Type.Array(PieceAuthProperty)])),
version: Type.String(),
categories: Type.Optional(Type.Array(Type.Enum(PieceCategory))),
minimumSupportedRelease: Type.Optional(Type.String()),
maximumSupportedRelease: Type.Optional(Type.String()),
i18n:I18nForPiece,
})
export type PieceBase = {
id?: string;
name: string;
displayName: string;
logoUrl: string;
description: string;
projectId?: ProjectId;
platformId?: string;
authors: string[],
directoryPath?: string;
auth?: PieceAuthProperty | PieceAuthProperty[];
version: string;
categories?: PieceCategory[];
minimumSupportedRelease?: string;
maximumSupportedRelease?: string;
i18n?: Partial<Record<LocalesEnum, Record<string, string>>>
// this method didn't exist in older version
getContextInfo: (() => { version: ContextVersion }) | undefined;
}
export const ActionBase = Type.Object({
name: Type.String(),
displayName: Type.String(),
description: Type.String(),
props: PiecePropertyMap,
requireAuth: Type.Boolean(),
errorHandlingOptions: Type.Optional(ErrorHandlingOptionsParam),
})
export type ActionBase = {
name: string,
displayName: string,
description: string,
props: PiecePropertyMap,
requireAuth: boolean;
errorHandlingOptions?: ErrorHandlingOptionsParam;
}
export const TriggerBase = Type.Composite([
Type.Omit(ActionBase, ["requireAuth"]),
Type.Object({
type: Type.Enum(TriggerStrategy),
sampleData: Type.Unknown(),
handshakeConfiguration: Type.Optional(WebhookHandshakeConfiguration),
renewConfiguration: Type.Optional(WebhookRenewConfiguration),
testStrategy: Type.Enum(TriggerTestStrategy),
})
])
export type TriggerBase = ActionBase & {
type: TriggerStrategy;
sampleData: unknown,
handshakeConfiguration?: WebhookHandshakeConfiguration;
renewConfiguration?: WebhookRenewConfiguration;
testStrategy: TriggerTestStrategy;
};
export const PieceMetadata = Type.Composite([
PieceBase,
Type.Object({
actions: Type.Record(Type.String(), ActionBase),
triggers: Type.Record(Type.String(), TriggerBase),
})
])
export type PieceMetadata = Omit<PieceBase, 'getContextInfo'> & {
actions: Record<string, ActionBase>;
triggers: Record<string, TriggerBase>;
// this property didn't exist in older version
contextInfo: { version: ContextVersion } | undefined;
};
export const PieceMetadataSummary = Type.Composite([
Type.Omit(PieceMetadata, ["actions", "triggers"]),
Type.Object({
actions: Type.Number(),
triggers: Type.Number(),
suggestedActions: Type.Optional(Type.Array(TriggerBase)),
suggestedTriggers: Type.Optional(Type.Array(ActionBase)),
})
])
export type PieceMetadataSummary = Omit<PieceMetadata, "actions" | "triggers"> & {
actions: number;
triggers: number;
suggestedActions?: ActionBase[];
suggestedTriggers?: TriggerBase[];
}
const PiecePackageMetadata = Type.Object({
projectUsage: Type.Number(),
tags: Type.Optional(Type.Array(Type.String())),
pieceType: Type.Enum(PieceType),
packageType: Type.Enum(PackageType),
platformId: Type.Optional(Type.String()),
archiveId: Type.Optional(Type.String()),
})
type PiecePackageMetadata = Static<typeof PiecePackageMetadata>
export const PieceMetadataModel = Type.Composite([
PieceMetadata,
PiecePackageMetadata
])
export type PieceMetadataModel = PieceMetadata & PiecePackageMetadata
export const PieceMetadataModelSummary = Type.Composite([
PieceMetadataSummary,
PiecePackageMetadata
])
export type PieceMetadataModelSummary = PieceMetadataSummary & PiecePackageMetadata;
export const PiecePackageInformation = Type.Object({
name: Type.String(),
version: Type.String(),
})
export type PiecePackageInformation = Static<typeof PiecePackageInformation>

View File

@@ -0,0 +1,132 @@
import { Trigger } from './trigger/trigger';
import { Action } from './action/action';
import {
EventPayload,
ParseEventResponse,
PieceCategory,
} from '@activepieces/shared';
import { PieceBase, PieceMetadata} from './piece-metadata';
import { PieceAuthProperty } from './property/authentication';
import { ServerContext } from './context';
import { ContextVersion, LATEST_CONTEXT_VERSION, MINIMUM_SUPPORTED_RELEASE_AFTER_LATEST_CONTEXT_VERSION } from './context/versioning';
import * as semver from 'semver';
export class Piece<PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = PieceAuthProperty>
implements Omit<PieceBase, 'version' | 'name'>
{
private readonly _actions: Record<string, Action> = {};
private readonly _triggers: Record<string, Trigger> = {};
// this method didn't exist in older version
public getContextInfo: (() => { version: ContextVersion } )| undefined = () => ({ version: LATEST_CONTEXT_VERSION });
constructor(
public readonly displayName: string,
public readonly logoUrl: string,
public readonly authors: string[],
public readonly events: PieceEventProcessors | undefined,
actions: Action[],
triggers: Trigger[],
public readonly categories: PieceCategory[],
public readonly auth?: PieceAuth,
public readonly minimumSupportedRelease: string = MINIMUM_SUPPORTED_RELEASE_AFTER_LATEST_CONTEXT_VERSION,
public readonly maximumSupportedRelease?: string,
public readonly description = '',
) {
if(!semver.valid(minimumSupportedRelease) || semver.lt(minimumSupportedRelease, MINIMUM_SUPPORTED_RELEASE_AFTER_LATEST_CONTEXT_VERSION)) {
this.minimumSupportedRelease = MINIMUM_SUPPORTED_RELEASE_AFTER_LATEST_CONTEXT_VERSION;
}
actions.forEach((action) => (this._actions[action.name] = action));
triggers.forEach((trigger) => (this._triggers[trigger.name] = trigger));
}
metadata(): BackwardCompatiblePieceMetadata {
return {
displayName: this.displayName,
logoUrl: this.logoUrl,
actions: this._actions,
triggers: this._triggers,
categories: this.categories,
description: this.description,
authors: this.authors,
auth: this.auth,
minimumSupportedRelease: this.minimumSupportedRelease,
maximumSupportedRelease: this.maximumSupportedRelease,
contextInfo: this.getContextInfo?.()
};
}
getAction(actionName: string): Action | undefined {
return this._actions[actionName];
}
getTrigger(triggerName: string): Trigger | undefined {
return this._triggers[triggerName];
}
actions() {
return this._actions;
}
triggers() {
return this._triggers;
}
}
export const createPiece = <PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined>(
params: CreatePieceParams<PieceAuth>
) => {
if(params.auth && Array.isArray(params.auth)) {
const isUnique = params.auth.every((auth, index, self) =>
index === self.findIndex((t) => t.type === auth.type)
);
if(!isUnique) {
throw new Error('Auth properties must be unique by type');
}
}
return new Piece<PieceAuth>(
params.displayName,
params.logoUrl,
params.authors ?? [],
params.events,
params.actions,
params.triggers,
params.categories ?? [],
params.auth,
params.minimumSupportedRelease,
params.maximumSupportedRelease,
params.description,
);
};
type CreatePieceParams<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined
> = {
displayName: string;
logoUrl: string;
authors: string[];
description?: string;
auth: PieceAuth | undefined;
events?: PieceEventProcessors;
minimumSupportedRelease?: string;
maximumSupportedRelease?: string;
actions: Action[];
triggers: Trigger[];
categories?: PieceCategory[];
};
type PieceEventProcessors = {
parseAndReply: (ctx: { payload: EventPayload, server: Omit<ServerContext, 'token' | 'apiUrl'> }) => ParseEventResponse;
verify: (ctx: {
webhookSecret: string | Record<string, string>;
payload: EventPayload;
appWebhookUrl: string;
}) => boolean;
};
type BackwardCompatiblePieceMetadata = Omit<PieceMetadata, 'name' | 'version' | 'authors' | 'i18n' | 'getContextInfo'> & {
authors?: PieceMetadata['authors']
i18n?: PieceMetadata['i18n']
}

View File

@@ -0,0 +1,44 @@
import { Static, Type } from '@sinclair/typebox';
import { TPropertyValue } from '../input/common';
import { PropertyType } from '../input/property-type';
import { BasePieceAuthSchema } from './common';
export const BasicAuthPropertyValue = Type.Object({
username: Type.String(),
password: Type.String(),
})
export type BasicAuthPropertyValue = Static<typeof BasicAuthPropertyValue>
export const BasicAuthProperty = Type.Composite([
BasePieceAuthSchema,
Type.Object({
username: Type.Object({
displayName: Type.String(),
description: Type.Optional(Type.String())
}),
password: Type.Object({
displayName: Type.String(),
description: Type.Optional(Type.String())
})
}),
TPropertyValue(BasicAuthPropertyValue, PropertyType.BASIC_AUTH)
])
export type BasicAuthProperty =
BasePieceAuthSchema<BasicAuthPropertyValue> & {
username: {
displayName: string;
description?: string;
};
password: {
displayName: string;
description?: string;
};
} &
TPropertyValue<
BasicAuthPropertyValue,
PropertyType.BASIC_AUTH,
true
>;

View File

@@ -0,0 +1,19 @@
import { Type } from '@sinclair/typebox';
import { ServerContext } from '../../context';
export const BasePieceAuthSchema = Type.Object({
displayName: Type.String(),
description: Type.Optional(Type.String())
});
export type BasePieceAuthSchema<AuthValueSchema> = {
displayName: string;
description?: string;
validate?: (params: { auth: AuthValueSchema; server: Omit<ServerContext, 'token'> }) => Promise<
| { valid: true }
| {
valid: false;
error: string;
}
>;
};

View File

@@ -0,0 +1,51 @@
import { Type } from '@sinclair/typebox';
import { TPropertyValue } from '../input/common';
import { PropertyType } from '../input/property-type';
import { LongTextProperty, ShortTextProperty } from '../input/text-property';
import { NumberProperty } from '../input/number-property';
import { CheckboxProperty } from '../input/checkbox-property';
import { StaticDropdownProperty, StaticMultiSelectDropdownProperty } from '../input/dropdown/static-dropdown';
import { StaticPropsValue } from '..';
import { SecretTextProperty } from './secret-text-property';
import { BasePieceAuthSchema } from './common';
import { MarkDownProperty } from '../input/markdown-property';
const CustomAuthProps = Type.Record(Type.String(), Type.Union([
ShortTextProperty,
LongTextProperty,
NumberProperty,
CheckboxProperty,
StaticDropdownProperty,
]));
export type CustomAuthProps = Record<
string,
| ShortTextProperty<boolean>
| LongTextProperty<boolean>
| SecretTextProperty<boolean>
| NumberProperty<boolean>
| StaticDropdownProperty<unknown, boolean>
| CheckboxProperty<boolean>
| MarkDownProperty
| StaticMultiSelectDropdownProperty<unknown, boolean>
>;
export const CustomAuthProperty = Type.Composite([
BasePieceAuthSchema,
Type.Object({
props: CustomAuthProps,
}),
TPropertyValue(Type.Unknown(), PropertyType.CUSTOM_AUTH)
])
export type CustomAuthProperty<
T extends CustomAuthProps
> = BasePieceAuthSchema<StaticPropsValue<T>> & {
props: T;
} &
TPropertyValue<
StaticPropsValue<T>,
PropertyType.CUSTOM_AUTH,
true
>;

View File

@@ -0,0 +1,97 @@
import { Type } from "@sinclair/typebox";
import { BasicAuthProperty } from "./basic-auth-prop";
import { CustomAuthProperty, CustomAuthProps } from "./custom-auth-prop";
import { SecretTextProperty } from "./secret-text-property";
import { PropertyType } from "../input/property-type";
import { OAuth2Property, OAuth2Props } from "./oauth2-prop";
import { AppConnectionType, isNil } from "@activepieces/shared";
export const PieceAuthProperty = Type.Union([
BasicAuthProperty,
CustomAuthProperty,
OAuth2Property,
SecretTextProperty,
])
export type PieceAuthProperty = BasicAuthProperty | CustomAuthProperty<any> | OAuth2Property<any> | SecretTextProperty<boolean>;
type AuthProperties<T> = Omit<Properties<T>, 'displayName'> & {
displayName?: string;
};
type Properties<T> = Omit<
T,
'valueSchema' | 'type' | 'defaultValidators' | 'defaultProcessors'
>;
export const DEFAULT_CONNECTION_DISPLAY_NAME = 'Connection';
export const PieceAuth = {
SecretText<R extends boolean>(
request: Properties<SecretTextProperty<R>>
): R extends true ? SecretTextProperty<true> : SecretTextProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.SECRET_TEXT,
} as unknown as R extends true ? SecretTextProperty<true> : SecretTextProperty<false>;
},
OAuth2<T extends OAuth2Props>(
request: AuthProperties<OAuth2Property<T>>
): OAuth2Property<T> {
return {
...request,
valueSchema: undefined,
type: PropertyType.OAUTH2,
displayName: request.displayName || DEFAULT_CONNECTION_DISPLAY_NAME,
} as unknown as OAuth2Property<T>
},
BasicAuth(
request: AuthProperties<BasicAuthProperty>
): BasicAuthProperty {
return {
...request,
valueSchema: undefined,
type: PropertyType.BASIC_AUTH,
displayName: request.displayName || DEFAULT_CONNECTION_DISPLAY_NAME,
required: true,
} as unknown as BasicAuthProperty;
},
CustomAuth<T extends CustomAuthProps>(
request: AuthProperties<CustomAuthProperty<T>>
): CustomAuthProperty<T> {
return {
...request,
valueSchema: undefined,
type: PropertyType.CUSTOM_AUTH,
displayName: request.displayName || DEFAULT_CONNECTION_DISPLAY_NAME,
} as unknown as CustomAuthProperty<T>
},
None() {
return undefined;
},
};
export type ExtractPieceAuthPropertyTypeForMethods<T extends PieceAuthProperty | PieceAuthProperty[] | undefined> = T extends PieceAuthProperty[] ? T[number] : T extends undefined ? undefined : T;
export function getAuthPropertyForValue({ authValueType, pieceAuth }: GetAuthPropertyForValue) {
if (!Array.isArray(pieceAuth) || isNil(pieceAuth)) {
return pieceAuth;
}
return pieceAuth.find(auth => authConnectionTypeToPropertyType[authValueType] === auth.type);
}
type GetAuthPropertyForValue = {
authValueType: AppConnectionType
pieceAuth: PieceAuthProperty | PieceAuthProperty[] | undefined
}
const authConnectionTypeToPropertyType: Record<AppConnectionType, PropertyType | undefined> = {
[AppConnectionType.OAUTH2]: PropertyType.OAUTH2,
[AppConnectionType.CLOUD_OAUTH2]: PropertyType.OAUTH2,
[AppConnectionType.PLATFORM_OAUTH2]: PropertyType.OAUTH2,
[AppConnectionType.BASIC_AUTH]: PropertyType.BASIC_AUTH,
[AppConnectionType.CUSTOM_AUTH]: PropertyType.CUSTOM_AUTH,
[AppConnectionType.SECRET_TEXT]: PropertyType.SECRET_TEXT,
[AppConnectionType.NO_AUTH]: undefined,
}

View File

@@ -0,0 +1,90 @@
import { BOTH_CLIENT_CREDENTIALS_AND_AUTHORIZATION_CODE, OAuth2GrantType } from '@activepieces/shared';
import { Type } from '@sinclair/typebox';
import { ShortTextProperty } from '../input/text-property';
import { SecretTextProperty } from './secret-text-property';
import { BasePieceAuthSchema } from './common';
import { TPropertyValue } from '../input/common';
import { PropertyType } from '../input/property-type';
import { StaticDropdownProperty } from '../input/dropdown/static-dropdown';
import { StaticPropsValue } from '..';
export enum OAuth2AuthorizationMethod {
HEADER = 'HEADER',
BODY = 'BODY',
}
const OAuthProp = Type.Union([
ShortTextProperty,
SecretTextProperty,
StaticDropdownProperty,
])
type OAuthProp =
| ShortTextProperty<boolean>
| SecretTextProperty<boolean>
| StaticDropdownProperty<any, boolean>;
export const OAuth2Props = Type.Record(Type.String(), OAuthProp);
export type OAuth2Props = {
[key: string]: OAuthProp;
}
type OAuthPropsValue<T extends OAuth2Props> = StaticPropsValue<T>;
const OAuth2ExtraProps = Type.Object({
props: Type.Optional(Type.Record(Type.String(), OAuthProp)),
authUrl: Type.String(),
tokenUrl: Type.String(),
scope: Type.Array(Type.String()),
prompt: Type.Optional(Type.Union([Type.Literal('none'), Type.Literal('consent'), Type.Literal('login'), Type.Literal('omit')])),
pkce: Type.Optional(Type.Boolean()),
pkceMethod: Type.Optional(Type.Union([Type.Literal('plain'), Type.Literal('S256')])),
authorizationMethod: Type.Optional(Type.Enum(OAuth2AuthorizationMethod)),
grantType: Type.Optional(Type.Union([Type.Enum(OAuth2GrantType), Type.Literal(BOTH_CLIENT_CREDENTIALS_AND_AUTHORIZATION_CODE)])),
extra: Type.Optional(Type.Record(Type.String(), Type.String())),
})
type OAuth2ExtraProps = {
props?: OAuth2Props
authUrl: string
tokenUrl: string
scope: string[]
prompt?: 'none' | 'consent' | 'login' | 'omit'
pkce?: boolean
pkceMethod?: 'plain' | 'S256'
authorizationMethod?: OAuth2AuthorizationMethod
grantType?: OAuth2GrantType | typeof BOTH_CLIENT_CREDENTIALS_AND_AUTHORIZATION_CODE
extra?: Record<string, string>,
}
export const OAuth2PropertyValue = Type.Object({
access_token: Type.String(),
props: Type.Optional(OAuth2Props),
data: Type.Record(Type.String(), Type.Any())
})
export type OAuth2PropertyValue<T extends OAuth2Props = any> = {
access_token: string;
props?: OAuthPropsValue<T>;
data: Record<string, any>;
};
export const OAuth2Property = Type.Composite([
BasePieceAuthSchema,
OAuth2ExtraProps,
TPropertyValue(OAuth2PropertyValue, PropertyType.OAUTH2)
])
export type OAuth2Property<
T extends OAuth2Props
> = BasePieceAuthSchema<OAuth2PropertyValue<T>> &
OAuth2ExtraProps &
TPropertyValue<
OAuth2PropertyValue<T>,
PropertyType.OAUTH2,
true
>;

View File

@@ -0,0 +1,20 @@
import { Type } from "@sinclair/typebox";
import { BasePieceAuthSchema } from "./common";
import { TPropertyValue } from "../input/common";
import { PropertyType } from "../input/property-type";
export const SecretTextProperty = Type.Composite([
BasePieceAuthSchema,
TPropertyValue(Type.Object({
auth: Type.String()
}), PropertyType.SECRET_TEXT)
])
export type SecretTextProperty<R extends boolean> =
BasePieceAuthSchema<string> &
TPropertyValue<
string,
PropertyType.SECRET_TEXT,
R
>;

View File

@@ -0,0 +1,72 @@
import { InputProperty } from './input';
import { PieceAuthProperty } from './authentication';
import { TSchema, Type } from '@sinclair/typebox';
import { PropertyType } from './input/property-type';
import { DropdownState } from './input/dropdown/common';
import { AUTHENTICATION_PROPERTY_NAME, isEmpty, isNil } from '@activepieces/shared';
// EXPORTED
export { ApFile } from './input/file-property';
export { DropdownProperty, MultiSelectDropdownProperty } from './input/dropdown/dropdown-prop';
export { DynamicProperties, DynamicProp } from './input/dynamic-prop';
export { PropertyType } from './input/property-type';
export { Property } from './input';
export { PieceAuth,getAuthPropertyForValue } from './authentication';
export type { ExtractPieceAuthPropertyTypeForMethods } from './authentication';
export { DynamicPropsValue } from './input/dynamic-prop';
export { DropdownOption,DropdownState } from './input/dropdown/common';
export { OAuth2PropertyValue } from './authentication/oauth2-prop';
export { PieceAuthProperty, DEFAULT_CONNECTION_DISPLAY_NAME} from './authentication';
export { ShortTextProperty } from './input/text-property';
export { ArrayProperty, ArraySubProps } from './input/array-property';
export { BasePropertySchema } from './input/common';
export { CheckboxProperty } from './input/checkbox-property';
export { DateTimeProperty } from './input/date-time-property';
export { LongTextProperty } from './input/text-property';
export { NumberProperty } from './input/number-property';
export { ObjectProperty } from './input/object-property';
export { OAuth2Props } from './authentication/oauth2-prop';
export { OAuth2AuthorizationMethod } from './authentication/oauth2-prop';
export { BasicAuthPropertyValue } from './authentication/basic-auth-prop';
export { StaticMultiSelectDropdownProperty } from './input/dropdown/static-dropdown';
export { StaticDropdownProperty } from './input/dropdown/static-dropdown';
export * from './authentication/custom-auth-prop';
export { OAuth2Property } from './authentication/oauth2-prop';
export { FileProperty } from './input/file-property';
export { BasicAuthProperty } from './authentication/basic-auth-prop';
export { SecretTextProperty } from './authentication/secret-text-property'
export { CustomAuthProperty } from './authentication/custom-auth-prop';
export { JsonProperty } from './input/json-property'
export const PieceProperty = Type.Union([InputProperty, PieceAuthProperty])
export type PieceProperty = InputProperty | PieceAuthProperty;
export {CustomProperty} from './input/custom-property'
export type {CustomPropertyCodeFunctionParams} from './input/custom-property'
export const PiecePropertyMap = Type.Record(Type.String(), PieceProperty)
export interface PiecePropertyMap {
[name: string]: PieceProperty;
}
export type { InputProperty } from './input';
export const InputPropertyMap = Type.Record(Type.String(), InputProperty)
export interface InputPropertyMap {
[name: string]: InputProperty;
}
export { piecePropertiesUtils } from './util';
export type PiecePropValueSchema<T extends PieceProperty> =
T extends undefined
? undefined
: T extends { required: true }
? T['valueSchema']
: T['valueSchema'] | undefined;
export type StaticPropsValue<T extends PiecePropertyMap> = {
[P in keyof T]: PiecePropValueSchema<T[P]>;
};
export type ExecutePropsResult<T extends PropertyType.DROPDOWN | PropertyType.MULTI_SELECT_DROPDOWN | PropertyType.DYNAMIC> = {
type: T
options: T extends PropertyType.DROPDOWN ? DropdownState<unknown> : T extends PropertyType.MULTI_SELECT_DROPDOWN ? DropdownState<unknown> : InputPropertyMap
}

View File

@@ -0,0 +1,52 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
import { LongTextProperty, ShortTextProperty } from "./text-property";
import { StaticDropdownProperty, StaticMultiSelectDropdownProperty } from "./dropdown/static-dropdown";
import { MultiSelectDropdownProperty } from "./dropdown/dropdown-prop";
import { CheckboxProperty } from "./checkbox-property";
import { NumberProperty } from "./number-property";
import { FileProperty } from "./file-property";
import { JsonProperty } from './json-property';
import { ColorProperty } from "./color-property";
import { DateTimeProperty } from './date-time-property';
export const ArraySubProps = Type.Record(Type.String(), Type.Union([
ShortTextProperty,
LongTextProperty,
StaticDropdownProperty,
MultiSelectDropdownProperty,
StaticMultiSelectDropdownProperty,
CheckboxProperty,
NumberProperty,
FileProperty,
DateTimeProperty,
]))
export const ArrayProperty = Type.Composite([
BasePropertySchema,
Type.Object({
properties: ArraySubProps
}),
TPropertyValue(Type.Array(Type.Unknown()), PropertyType.ARRAY)
])
export type ArraySubProps<R extends boolean> = Record<
string,
| ShortTextProperty<R>
| LongTextProperty<R>
| StaticDropdownProperty<any, R>
| MultiSelectDropdownProperty<any, R>
| StaticMultiSelectDropdownProperty<any, R>
| CheckboxProperty<R>
| NumberProperty<R>
| FileProperty<R>
| JsonProperty<R>
| ColorProperty<R>
| DateTimeProperty<R>
>;
export type ArrayProperty<R extends boolean> = BasePropertySchema &
{
properties?: ArraySubProps<R>;
} & TPropertyValue<unknown[], PropertyType.ARRAY, R>;

View File

@@ -0,0 +1,11 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
export const CheckboxProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.Boolean(), PropertyType.CHECKBOX)
])
export type CheckboxProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<boolean, PropertyType.CHECKBOX, R>;

View File

@@ -0,0 +1,12 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
export const ColorProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.String(), PropertyType.COLOR)
])
export type ColorProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<string, PropertyType.COLOR, R>;

View File

@@ -0,0 +1,57 @@
import { Static, TObject, TSchema, Type } from "@sinclair/typebox";
import { ApFile } from "./file-property";
import { PropertyType } from "./property-type";
export const BasePropertySchema = Type.Object({
displayName: Type.String(),
description: Type.Optional(Type.String())
})
export type BasePropertySchema = Static<typeof BasePropertySchema>
export const TPropertyValue = <T extends TSchema, U extends PropertyType>(T: T, propertyType: U): TObject => Type.Object({
type: Type.Literal(propertyType),
required: Type.Boolean(),
defaultValue: Type.Optional(Type.Any()),
})
export type TPropertyValue<
T,
U extends PropertyType,
REQUIRED extends boolean
> = {
valueSchema: T;
type: U;
required: REQUIRED;
// TODO this should be T or undefined
defaultValue?: U extends PropertyType.ARRAY
? unknown[]
: U extends PropertyType.JSON
? object
: U extends PropertyType.CHECKBOX
? boolean
: U extends PropertyType.LONG_TEXT
? string
: U extends PropertyType.SHORT_TEXT
? string
: U extends PropertyType.NUMBER
? number
: U extends PropertyType.DROPDOWN
? unknown
: U extends PropertyType.MULTI_SELECT_DROPDOWN
? unknown[]
: U extends PropertyType.STATIC_MULTI_SELECT_DROPDOWN
? unknown[]
: U extends PropertyType.STATIC_DROPDOWN
? unknown
: U extends PropertyType.DATE_TIME
? string
: U extends PropertyType.FILE
? ApFile
: U extends PropertyType.COLOR
? string
: unknown;
};

View File

@@ -0,0 +1,32 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
// Code should be a valid javascript function that takes a single argument which is an object
/*
(ctx: {containerId:string, value: unknown, onChange: (value: unknown) => void, isEmbeded: boolean, projectId:string}) => void
*/
export const CustomProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.Unknown(), PropertyType.CUSTOM),
Type.Object({
code: Type.String(),
})
])
export type CustomProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<unknown, PropertyType.CUSTOM, R> & {
code:string;
}
export type CustomPropertyCodeFunctionParams =
{
containerId:string,
value: unknown,
onChange: (value: unknown) => void,
isEmbeded: boolean,
projectId:string,
property: Pick<CustomProperty<boolean>, 'displayName' | 'description' | 'required'>,
disabled: boolean
}

View File

@@ -0,0 +1,11 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
export const DateTimeProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.String(), PropertyType.DATE_TIME)
])
export type DateTimeProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<string, PropertyType.DATE_TIME, R>;

View File

@@ -0,0 +1,26 @@
import { Type } from "@sinclair/typebox";
export const DropdownOption = Type.Object({
label: Type.String(),
value: Type.Unknown(),
})
export type DropdownOption<T> = {
label: string;
value: T;
}
export const DropdownState = Type.Object({
disabled: Type.Optional(Type.Boolean()),
placeholder: Type.Optional(Type.String()),
options: Type.Array(DropdownOption)
})
export type DropdownState<T> = {
disabled?: boolean;
placeholder?: string;
options: DropdownOption<T>[];
}

View File

@@ -0,0 +1,58 @@
import { BasePropertySchema, TPropertyValue } from "../common";
import { DropdownState } from "./common";
import { AppConnectionValueForAuthProperty, PropertyContext } from "../../../context";
import { Type } from "@sinclair/typebox";
import { PropertyType } from "../property-type";
import { PieceAuthProperty } from "../../authentication";
type DynamicDropdownOptions<T, PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined> = (
propsValue: Record<string, unknown> & {
auth?: PieceAuth extends undefined ? undefined : AppConnectionValueForAuthProperty<Exclude<PieceAuth, undefined>>;
},
ctx: PropertyContext,
) => Promise<DropdownState<T>>;
export const DropdownProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.Unknown(), PropertyType.DROPDOWN),
Type.Object({
refreshers: Type.Array(Type.String()),
}),
]);
export type DropdownProperty<T, R extends boolean, PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined> = BasePropertySchema & {
/**
* A dummy property used to infer {@code PieceAuth} type
*/
auth: PieceAuth;
refreshers: string[];
refreshOnSearch?: boolean;
options: DynamicDropdownOptions<T, PieceAuth>;
} & TPropertyValue<T, PropertyType.DROPDOWN, R>;
export const MultiSelectDropdownProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.Array(Type.Unknown()), PropertyType.MULTI_SELECT_DROPDOWN),
Type.Object({
refreshers: Type.Array(Type.String()),
}),
]);
export type MultiSelectDropdownProperty<
T,
R extends boolean,
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined
> = BasePropertySchema & {
/**
* A dummy property used to infer {@code PieceAuth} type
*/
auth: PieceAuth;
refreshers: string[];
refreshOnSearch?: boolean;
options: DynamicDropdownOptions<T, PieceAuth>;
} & TPropertyValue<
T[],
PropertyType.MULTI_SELECT_DROPDOWN,
R
>;

View File

@@ -0,0 +1,39 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "../common";
import { DropdownState } from "./common";
import { PropertyType } from "../property-type";
export const StaticDropdownProperty = Type.Composite([
BasePropertySchema,
Type.Object({
options: DropdownState
}),
TPropertyValue(Type.Unknown(), PropertyType.STATIC_DROPDOWN)
])
export type StaticDropdownProperty<
T,
R extends boolean
> = BasePropertySchema & {
options: DropdownState<T>;
} & TPropertyValue<T, PropertyType.STATIC_DROPDOWN, R>;
export const StaticMultiSelectDropdownProperty = Type.Composite([
BasePropertySchema,
Type.Object({
options: DropdownState
}),
TPropertyValue(Type.Array(Type.Unknown()), PropertyType.STATIC_MULTI_SELECT_DROPDOWN)
])
export type StaticMultiSelectDropdownProperty<
T,
R extends boolean
> = BasePropertySchema & {
options: DropdownState<T>;
} & TPropertyValue<
T[],
PropertyType.STATIC_MULTI_SELECT_DROPDOWN,
R
>;

View File

@@ -0,0 +1,56 @@
import { Type } from "@sinclair/typebox";
import { StaticDropdownProperty, StaticMultiSelectDropdownProperty } from "./dropdown/static-dropdown";
import { ShortTextProperty } from "./text-property";
import { BasePropertySchema, TPropertyValue } from "./common";
import { AppConnectionValueForAuthProperty, PropertyContext } from "../../context";
import { PropertyType } from "./property-type";
import { JsonProperty } from "./json-property";
import { ArrayProperty } from "./array-property";
import { ExtractPieceAuthPropertyTypeForMethods, InputPropertyMap, PieceAuthProperty } from "..";
export const DynamicProp = Type.Union([
ShortTextProperty,
StaticDropdownProperty,
JsonProperty,
ArrayProperty,
StaticMultiSelectDropdownProperty,
])
export type DynamicProp =
| ShortTextProperty<boolean>
| StaticDropdownProperty<any, boolean>
| JsonProperty<boolean>
| ArrayProperty<boolean>
| StaticMultiSelectDropdownProperty<any, boolean>;
export const DynamicPropsValue = Type.Record(Type.String(), DynamicProp);
export type DynamicPropsValue = Record<string, DynamicProp['valueSchema']>;
export const DynamicProperties = Type.Composite([
Type.Object({
refreshers: Type.Array(Type.String()),
}),
BasePropertySchema,
TPropertyValue(Type.Unknown(), PropertyType.DYNAMIC),
])
export type DynamicProperties<R extends boolean, PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined> = BasePropertySchema &
{
//dummy property to define auth property value inside props value
auth: PieceAuth
props: DynamicPropertiesOptions<PieceAuth>
refreshers: string[];
} &
TPropertyValue<
DynamicPropsValue,
PropertyType.DYNAMIC,
R
>;
type DynamicPropertiesOptions<PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined> = (
propsValue: Record<string, unknown> & {
auth?: AppConnectionValueForAuthProperty<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>>;
},
ctx: PropertyContext,
) => Promise<InputPropertyMap>;

View File

@@ -0,0 +1,23 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
export class ApFile {
constructor(
public filename: string,
public data: Buffer,
public extension?: string
) { }
get base64(): string {
return this.data.toString('base64');
}
}
export const FileProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.Unknown(), PropertyType.FILE)
])
export type FileProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<ApFile, PropertyType.FILE, R>;

View File

@@ -0,0 +1,271 @@
import { Type } from '@sinclair/typebox';
import { ArrayProperty } from './array-property';
import { CheckboxProperty } from './checkbox-property';
import { DateTimeProperty } from './date-time-property';
import {
DropdownProperty,
MultiSelectDropdownProperty,
} from './dropdown/dropdown-prop';
import {
StaticDropdownProperty,
StaticMultiSelectDropdownProperty,
} from './dropdown/static-dropdown';
import { DynamicProperties } from './dynamic-prop';
import { FileProperty } from './file-property';
import { JsonProperty } from './json-property';
import { MarkDownProperty } from './markdown-property';
import { MarkdownVariant } from '@activepieces/shared';
import { NumberProperty } from './number-property';
import { ObjectProperty } from './object-property';
import { PropertyType } from './property-type';
import { LongTextProperty, ShortTextProperty } from './text-property';
import { CustomProperty, CustomPropertyCodeFunctionParams } from './custom-property';
import { ColorProperty } from './color-property';
import { PieceAuthProperty } from '../authentication';
export const InputProperty = Type.Union([
ShortTextProperty,
LongTextProperty,
MarkDownProperty,
CheckboxProperty,
StaticDropdownProperty,
StaticMultiSelectDropdownProperty,
DropdownProperty,
MultiSelectDropdownProperty,
DynamicProperties,
NumberProperty,
ArrayProperty,
ObjectProperty,
JsonProperty,
DateTimeProperty,
FileProperty,
ColorProperty,
]);
export type InputProperty =
| ShortTextProperty<boolean>
| LongTextProperty<boolean>
| MarkDownProperty
| CheckboxProperty<boolean>
| DropdownProperty<any, boolean, PieceAuthProperty | undefined | PieceAuthProperty[]>
| StaticDropdownProperty<any, boolean>
| NumberProperty<boolean>
| ArrayProperty<boolean>
| ObjectProperty<boolean>
| JsonProperty<boolean>
| MultiSelectDropdownProperty<unknown, boolean, PieceAuthProperty | undefined | PieceAuthProperty[]>
| StaticMultiSelectDropdownProperty<unknown, boolean>
| DynamicProperties<boolean, PieceAuthProperty | PieceAuthProperty[] | undefined>
| DateTimeProperty<boolean>
| FileProperty<boolean>
| CustomProperty<boolean>
| ColorProperty<boolean>;
type Properties<T> = Omit<
T,
'valueSchema' | 'type' | 'defaultValidators' | 'defaultProcessors'
>;
export const Property = {
ShortText<R extends boolean>(
request: Properties<ShortTextProperty<R>>
): R extends true ? ShortTextProperty<true> : ShortTextProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.SHORT_TEXT,
} as unknown as R extends true
? ShortTextProperty<true>
: ShortTextProperty<false>;
},
Checkbox<R extends boolean>(
request: Properties<CheckboxProperty<R>>
): R extends true ? CheckboxProperty<true> : CheckboxProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.CHECKBOX,
} as unknown as R extends true
? CheckboxProperty<true>
: CheckboxProperty<false>;
},
LongText<R extends boolean>(
request: Properties<LongTextProperty<R>>
): R extends true ? LongTextProperty<true> : LongTextProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.LONG_TEXT,
} as unknown as R extends true
? LongTextProperty<true>
: LongTextProperty<false>;
},
MarkDown(request: {
value: string;
variant?: MarkdownVariant;
}): MarkDownProperty {
return {
displayName: 'Markdown',
required: false,
description: request.value,
type: PropertyType.MARKDOWN,
valueSchema: undefined as never,
variant: request.variant ?? MarkdownVariant.INFO,
};
},
Number<R extends boolean>(
request: Properties<NumberProperty<R>>
): R extends true ? NumberProperty<true> : NumberProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.NUMBER,
} as unknown as R extends true
? NumberProperty<true>
: NumberProperty<false>;
},
Json<R extends boolean>(
request: Properties<JsonProperty<R>>
): R extends true ? JsonProperty<true> : JsonProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.JSON,
} as unknown as R extends true ? JsonProperty<true> : JsonProperty<false>;
},
Array<R extends boolean>(
request: Properties<ArrayProperty<R>>
): R extends true ? ArrayProperty<true> : ArrayProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.ARRAY,
} as unknown as R extends true ? ArrayProperty<true> : ArrayProperty<false>;
},
Object<R extends boolean>(
request: Properties<ObjectProperty<R>>
): R extends true ? ObjectProperty<true> : ObjectProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.OBJECT,
} as unknown as R extends true
? ObjectProperty<true>
: ObjectProperty<false>;
},
Dropdown<T, R extends boolean = boolean, PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined>(
request: Properties<DropdownProperty<T, R, PieceAuth>>
): R extends true ? DropdownProperty<T, true, PieceAuth> : DropdownProperty<T, false, PieceAuth> {
return {
...request,
valueSchema: undefined,
type: PropertyType.DROPDOWN,
} as unknown as R extends true
? DropdownProperty<T, true, PieceAuth>
: DropdownProperty<T, false, PieceAuth>;
},
StaticDropdown<T, R extends boolean = boolean>(
request: Properties<StaticDropdownProperty<T, R>>
): R extends true
? StaticDropdownProperty<T, true>
: StaticDropdownProperty<T, false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.STATIC_DROPDOWN,
} as unknown as R extends true
? StaticDropdownProperty<T, true>
: StaticDropdownProperty<T, false>;
},
MultiSelectDropdown<T, R extends boolean = boolean, PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined>(
request: Properties<MultiSelectDropdownProperty<T, R, PieceAuth>>
): R extends true
? MultiSelectDropdownProperty<T, true, PieceAuth>
: MultiSelectDropdownProperty<T, false, PieceAuth> {
return {
...request,
valueSchema: undefined,
type: PropertyType.MULTI_SELECT_DROPDOWN,
} as unknown as R extends true
? MultiSelectDropdownProperty<T, true, PieceAuth>
: MultiSelectDropdownProperty<T, false, PieceAuth>;
},
DynamicProperties<R extends boolean = boolean, PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = undefined>(
request: Properties<DynamicProperties<R,PieceAuth>>
): R extends true ? DynamicProperties<true, PieceAuth> : DynamicProperties<false, PieceAuth> {
return {
...request,
valueSchema: undefined,
type: PropertyType.DYNAMIC,
} as unknown as R extends true
? DynamicProperties<true, PieceAuth>
: DynamicProperties<false, PieceAuth>;
},
StaticMultiSelectDropdown<T, R extends boolean = boolean>(
request: Properties<StaticMultiSelectDropdownProperty<T, R>>
): R extends true
? StaticMultiSelectDropdownProperty<T, true>
: StaticMultiSelectDropdownProperty<T, false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.STATIC_MULTI_SELECT_DROPDOWN,
} as unknown as R extends true
? StaticMultiSelectDropdownProperty<T, true>
: StaticMultiSelectDropdownProperty<T, false>;
},
DateTime<R extends boolean>(
request: Properties<DateTimeProperty<R>>
): R extends true ? DateTimeProperty<true> : DateTimeProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.DATE_TIME,
} as unknown as R extends true
? DateTimeProperty<true>
: DateTimeProperty<false>;
},
File<R extends boolean>(
request: Properties<FileProperty<R>>
): R extends true ? FileProperty<true> : FileProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.FILE,
} as unknown as R extends true ? FileProperty<true> : FileProperty<false>;
},
Custom<R extends boolean>(
request: Omit<Properties<CustomProperty<R>>, 'code'> & {
/**
* This is designed to be self-contained and operates independently of any
* external libraries or imported dependencies. All necessary logic and
* functionality are implemented within this function itself.
*
* You can return a cleanup function that will be called when the component is unmounted in the frontend.
* */
code: ((ctx: CustomPropertyCodeFunctionParams) => (()=>void) | void)
}
): R extends true ? CustomProperty<true> : CustomProperty<false> {
const code = request.code.toString();
return {
...request,
code,
valueSchema: undefined,
type: PropertyType.CUSTOM,
} as unknown as R extends true ? CustomProperty<true> : CustomProperty<false>;
},
Color<R extends boolean>(
request: Properties<ColorProperty<R>>
): R extends true ? ColorProperty<true> : ColorProperty<false> {
return {
...request,
valueSchema: undefined,
type: PropertyType.COLOR,
} as unknown as R extends true
? ColorProperty<true>
: ColorProperty<false>;
},
};

View File

@@ -0,0 +1,17 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
export const JsonProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(
Type.Union([Type.Record(Type.String(), Type.Unknown())]),
PropertyType.JSON,
),
]);
export type JsonProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<
Record<string, unknown>,
PropertyType.JSON,
R
>;

View File

@@ -0,0 +1,18 @@
import { Type } from '@sinclair/typebox';
import { BasePropertySchema, TPropertyValue } from './common';
import { PropertyType } from './property-type';
import { MarkdownVariant } from '@activepieces/shared';
export const MarkDownProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.Void(), PropertyType.MARKDOWN),
]);
export type MarkDownProperty = BasePropertySchema &
TPropertyValue<
undefined,
PropertyType.MARKDOWN,
false
> & {
variant?: MarkdownVariant;
};

View File

@@ -0,0 +1,11 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
export const NumberProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.Number(), PropertyType.NUMBER)
])
export type NumberProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<number, PropertyType.NUMBER, R>;

View File

@@ -0,0 +1,18 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
export const ObjectProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(
Type.Record(Type.String(), Type.Unknown()),
PropertyType.OBJECT,
)
])
export type ObjectProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<
Record<string, unknown>,
PropertyType.OBJECT,
R
>;

View File

@@ -0,0 +1,23 @@
export enum PropertyType {
SHORT_TEXT = 'SHORT_TEXT',
LONG_TEXT = 'LONG_TEXT',
MARKDOWN = 'MARKDOWN',
DROPDOWN = 'DROPDOWN',
STATIC_DROPDOWN = 'STATIC_DROPDOWN',
NUMBER = 'NUMBER',
CHECKBOX = 'CHECKBOX',
OAUTH2 = 'OAUTH2',
SECRET_TEXT = 'SECRET_TEXT',
ARRAY = 'ARRAY',
OBJECT = 'OBJECT',
BASIC_AUTH = 'BASIC_AUTH',
JSON = 'JSON',
MULTI_SELECT_DROPDOWN = 'MULTI_SELECT_DROPDOWN',
STATIC_MULTI_SELECT_DROPDOWN = 'STATIC_MULTI_SELECT_DROPDOWN',
DYNAMIC = 'DYNAMIC',
CUSTOM_AUTH = 'CUSTOM_AUTH',
DATE_TIME = 'DATE_TIME',
FILE = 'FILE',
CUSTOM = 'CUSTOM',
COLOR = 'COLOR',
}

View File

@@ -0,0 +1,22 @@
import { Type } from "@sinclair/typebox";
import { BasePropertySchema, TPropertyValue } from "./common";
import { PropertyType } from "./property-type";
export const ShortTextProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.String(), PropertyType.SHORT_TEXT)
])
export type ShortTextProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<string, PropertyType.SHORT_TEXT, R>;
export const LongTextProperty = Type.Composite([
BasePropertySchema,
TPropertyValue(Type.String(), PropertyType.LONG_TEXT)
])
export type LongTextProperty<R extends boolean> = BasePropertySchema &
TPropertyValue<string, PropertyType.LONG_TEXT, R>;

View File

@@ -0,0 +1,131 @@
import { PiecePropertyMap } from ".";
import { PieceAuthProperty } from "./authentication";
import { PropertyType } from "./input/property-type";
import { Type, TSchema } from "@sinclair/typebox";
import { AUTHENTICATION_PROPERTY_NAME, isEmpty, isNil } from "@activepieces/shared";
function buildSchema(props: PiecePropertyMap, auth: PieceAuthProperty | PieceAuthProperty[] | undefined, requireAuth: boolean | undefined = true) {
const entries = Object.entries(props);
const nullableType = [Type.Null(), Type.Undefined()];
const nonNullableUnknownPropType = Type.Not(
Type.Union(nullableType),
Type.Unknown(),
);
const propsSchema: Record<string, TSchema> = {};
for (const [name, property] of entries) {
switch (property.type) {
case PropertyType.MARKDOWN:
propsSchema[name] = Type.Optional(
Type.Union([Type.Null(), Type.Undefined(), Type.Never(), Type.Unknown()]),
);
break;
case PropertyType.DATE_TIME:
case PropertyType.SHORT_TEXT:
case PropertyType.LONG_TEXT:
case PropertyType.COLOR:
case PropertyType.FILE:
propsSchema[name] = Type.String({
minLength: property.required ? 1 : undefined,
});
break;
case PropertyType.CHECKBOX:
propsSchema[name] = Type.Union([
Type.Boolean({ defaultValue: false }),
Type.String({}),
]);
break;
case PropertyType.NUMBER:
propsSchema[name] = Type.Union([
Type.String({
minLength: property.required ? 1 : undefined,
}),
Type.Number(),
]);
break;
case PropertyType.STATIC_DROPDOWN:
case PropertyType.DROPDOWN:
propsSchema[name] = nonNullableUnknownPropType;
break;
case PropertyType.BASIC_AUTH:
case PropertyType.CUSTOM_AUTH:
case PropertyType.SECRET_TEXT:
case PropertyType.OAUTH2:
break;
case PropertyType.ARRAY: {
const arrayItemSchema = isNil(property.properties)
? Type.String({
minLength: property.required ? 1 : undefined,
})
: buildSchema(property.properties,undefined);
propsSchema[name] = Type.Union([
Type.Array(arrayItemSchema, {
minItems: property.required ? 1 : undefined,
}),
//for inline items mode
Type.Record(Type.String(), Type.Unknown()),
//for normal dynamic input mode
Type.String({
minLength: property.required ? 1 : undefined,
}),
]);
break;
}
case PropertyType.OBJECT:
propsSchema[name] = Type.Union([
Type.Record(Type.String(), Type.Any()),
Type.String({
minLength: property.required ? 1 : undefined,
}),
]);
break;
case PropertyType.JSON:
propsSchema[name] = Type.Union([
Type.Record(Type.String(), Type.Any()),
Type.Array(Type.Any()),
Type.String({
minLength: property.required ? 1 : undefined,
}),
]);
break;
case PropertyType.MULTI_SELECT_DROPDOWN:
case PropertyType.STATIC_MULTI_SELECT_DROPDOWN:
propsSchema[name] = Type.Union([
Type.Array(Type.Any(), {
minItems: property.required ? 1 : undefined,
}),
Type.String({
minLength: property.required ? 1 : undefined,
}),
]);
break;
case PropertyType.DYNAMIC:
propsSchema[name] = Type.Record(Type.String(), Type.Any());
break;
case PropertyType.CUSTOM:
propsSchema[name] = Type.Unknown();
break;
}
//optional array is checked against its children
if (!property.required && property.type !== PropertyType.ARRAY) {
propsSchema[name] = Type.Optional(
Type.Union(
isEmpty(propsSchema[name])
? [Type.Any(), ...nullableType]
: [propsSchema[name], ...nullableType],
),
);
}
}
if(auth && requireAuth)
{
propsSchema[AUTHENTICATION_PROPERTY_NAME] = Type.String({
minLength: 1
})
}
return Type.Object(propsSchema);
}
export const piecePropertiesUtils = {
buildSchema
}

View File

@@ -0,0 +1,178 @@
import { Static, Type } from '@sinclair/typebox';
import { OnStartContext, TestOrRunHookContext, TriggerHookContext } from '../context';
import { TriggerBase } from '../piece-metadata';
import { InputPropertyMap } from '../property';
import { ExtractPieceAuthPropertyTypeForMethods, PieceAuthProperty } from '../property/authentication';
import { isNil, TriggerStrategy, TriggerTestStrategy, WebhookHandshakeConfiguration, WebhookHandshakeStrategy } from '@activepieces/shared';
export { TriggerStrategy }
export const DEDUPE_KEY_PROPERTY = '_dedupe_key'
export enum WebhookRenewStrategy {
CRON = 'CRON',
NONE = 'NONE',
}
type OnStartRunner<PieceAuth extends PieceAuthProperty | undefined, TriggerProps extends InputPropertyMap> = (ctx: OnStartContext<PieceAuth, TriggerProps>) => Promise<unknown | void>
export const WebhookRenewConfiguration = Type.Union([
Type.Object({
strategy: Type.Literal(WebhookRenewStrategy.CRON),
cronExpression: Type.String(),
}),
Type.Object({
strategy: Type.Literal(WebhookRenewStrategy.NONE),
}),
])
export type WebhookRenewConfiguration = Static<typeof WebhookRenewConfiguration>
export interface WebhookResponse {
status: number,
body?: any,
headers?: Record<string, string>
}
type BaseTriggerParams<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap,
TS extends TriggerStrategy,
> = {
name: string
displayName: string
description: string
requireAuth?: boolean
auth?: PieceAuth
props: TriggerProps
type: TS
onEnable: (context: TriggerHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<void>
onDisable: (context: TriggerHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<void>
run: (context: TestOrRunHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<unknown[]>
test?: (context: TestOrRunHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<unknown[]>,
onStart?: OnStartRunner<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps>,
sampleData: unknown
}
type WebhookTriggerParams<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap,
TS extends TriggerStrategy,
> = BaseTriggerParams<PieceAuth, TriggerProps, TS> & {
handshakeConfiguration?: WebhookHandshakeConfiguration
onHandshake?: (context: TriggerHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<WebhookResponse>,
renewConfiguration?: WebhookRenewConfiguration
onRenew?(context: TriggerHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>): Promise<void>,
}
type CreateTriggerParams<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap,
TS extends TriggerStrategy,
> = TS extends TriggerStrategy.WEBHOOK
? WebhookTriggerParams<PieceAuth, TriggerProps, TS>
: BaseTriggerParams<PieceAuth, TriggerProps, TS>
export class ITrigger<
TS extends TriggerStrategy,
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined,
TriggerProps extends InputPropertyMap,
> implements TriggerBase {
constructor(
public readonly name: string,
public readonly displayName: string,
public readonly description: string,
public readonly requireAuth: boolean,
public readonly props: TriggerProps,
public readonly type: TS,
public readonly handshakeConfiguration: WebhookHandshakeConfiguration,
public readonly onHandshake: (ctx: TriggerHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<WebhookResponse>,
public readonly renewConfiguration: WebhookRenewConfiguration,
public readonly onRenew: (ctx: TriggerHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<void>,
public readonly onEnable: (ctx: TriggerHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<void>,
public readonly onDisable: (ctx: TriggerHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<void>,
public readonly onStart: OnStartRunner<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps>,
public readonly run: (ctx: TestOrRunHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<unknown[]>,
public readonly test: (ctx: TestOrRunHookContext<ExtractPieceAuthPropertyTypeForMethods<PieceAuth>, TriggerProps, TS>) => Promise<unknown[]>,
public readonly sampleData: unknown,
public readonly testStrategy: TriggerTestStrategy,
) { }
}
export type Trigger<
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined = any,
TriggerProps extends InputPropertyMap = any,
S extends TriggerStrategy = any,
> = ITrigger<S, PieceAuth, TriggerProps>
// TODO refactor and extract common logic
export const createTrigger = <
TS extends TriggerStrategy,
PieceAuth extends PieceAuthProperty | PieceAuthProperty[] | undefined ,
TriggerProps extends InputPropertyMap,
>(params: CreateTriggerParams<PieceAuth, TriggerProps, TS>) => {
switch (params.type) {
case TriggerStrategy.WEBHOOK:
return new ITrigger(
params.name,
params.displayName,
params.description,
params.requireAuth ?? true,
params.props,
params.type,
params.handshakeConfiguration ?? { strategy: WebhookHandshakeStrategy.NONE },
params.onHandshake ?? (async () => ({ status: 200 })),
params.renewConfiguration ?? { strategy: WebhookRenewStrategy.NONE },
params.onRenew ?? (async () => Promise.resolve()),
params.onEnable,
params.onDisable,
params.onStart ?? (async () => Promise.resolve()),
params.run,
params.test ?? (() => Promise.resolve([params.sampleData])),
params.sampleData,
params.test ? TriggerTestStrategy.TEST_FUNCTION : TriggerTestStrategy.SIMULATION,
)
case TriggerStrategy.POLLING:
return new ITrigger(
params.name,
params.displayName,
params.description,
params.requireAuth ?? true,
params.props,
params.type,
{ strategy: WebhookHandshakeStrategy.NONE },
async () => ({ status: 200 }),
{ strategy: WebhookRenewStrategy.NONE },
(async () => Promise.resolve()),
params.onEnable,
params.onDisable,
params.onStart ?? (async () => Promise.resolve()),
params.run,
params.test ?? (() => Promise.resolve([params.sampleData])),
params.sampleData,
TriggerTestStrategy.TEST_FUNCTION,
)
case TriggerStrategy.APP_WEBHOOK:
return new ITrigger(
params.name,
params.displayName,
params.description,
params.requireAuth ?? true,
params.props,
params.type,
{ strategy: WebhookHandshakeStrategy.NONE },
async () => ({ status: 200 }),
{ strategy: WebhookRenewStrategy.NONE },
(async () => Promise.resolve()),
params.onEnable,
params.onDisable,
params.onStart ?? (async () => Promise.resolve()),
params.run,
params.test ?? (() => Promise.resolve([params.sampleData])),
params.sampleData,
(isNil(params.sampleData) && isNil(params.test)) ? TriggerTestStrategy.SIMULATION : TriggerTestStrategy.TEST_FUNCTION,
)
}
}