Skip to main content
Glama
piece-helper.ts9.96 kB
import { DropdownProperty, DynamicProperties, ExecutePropsResult, getAuthPropertyForValue, MultiSelectDropdownProperty, PieceAuthProperty, PieceMetadata, PiecePropertyMap, pieceTranslation, PropertyType, StaticPropsValue } from '@activepieces/pieces-framework' import { AppConnectionType, AppConnectionValue, EngineGenericError, ExecuteExtractPieceMetadata, ExecutePropsOptions, ExecuteValidateAuthOperation, ExecuteValidateAuthResponse, isNil, } from '@activepieces/shared' import { EngineConstants } from '../handler/context/engine-constants' import { testExecutionContext } from '../handler/context/test-execution-context' import { createFlowsContext } from '../services/flows.service' import { utils } from '../utils' import { createPropsResolver } from '../variables/props-resolver' import { pieceLoader } from './piece-loader' export const pieceHelper = { async executeProps( operation: ExecutePropsParams): Promise<ExecutePropsResult<PropertyType.DROPDOWN | PropertyType.MULTI_SELECT_DROPDOWN | PropertyType.DYNAMIC>> { const constants = EngineConstants.fromExecutePropertyInput(operation) const executionState = await testExecutionContext.stateFromFlowVersion({ apiUrl: operation.internalApiUrl, flowVersion: operation.flowVersion, projectId: operation.projectId, engineToken: operation.engineToken, sampleData: operation.sampleData, }) const { property, piece } = await pieceLoader.getPropOrThrow({ pieceName: operation.pieceName, pieceVersion: operation.pieceVersion, actionOrTriggerName: operation.actionOrTriggerName, propertyName: operation.propertyName, devPieces: EngineConstants.DEV_PIECES }) if (property.type !== PropertyType.DROPDOWN && property.type !== PropertyType.MULTI_SELECT_DROPDOWN && property.type !== PropertyType.DYNAMIC) { throw new EngineGenericError('PropertyTypeNotExecutableError', `Property type is not executable: ${property.type} for ${property.displayName}`) } const { data: executePropsResult, error: executePropsError } = await utils.tryCatchAndThrowOnEngineError((async (): Promise<ExecutePropsResult<PropertyType.DROPDOWN | PropertyType.MULTI_SELECT_DROPDOWN | PropertyType.DYNAMIC>> => { const { resolvedInput } = await createPropsResolver({ apiUrl: constants.internalApiUrl, projectId: constants.projectId, engineToken: constants.engineToken, contextVersion: piece.getContextInfo?.().version, }).resolve< StaticPropsValue<PiecePropertyMap> >({ unresolvedInput: operation.input, executionState, }) const ctx = { searchValue: operation.searchValue, server: { token: constants.engineToken, apiUrl: constants.internalApiUrl, publicUrl: operation.publicApiUrl, }, project: { id: constants.projectId, externalId: constants.externalProjectId, }, flows: createFlowsContext(constants), step: { name: operation.actionOrTriggerName, }, connections: utils.createConnectionManager({ projectId: constants.projectId, engineToken: constants.engineToken, apiUrl: constants.internalApiUrl, target: 'properties', contextVersion: piece.getContextInfo?.().version, }), } switch (property.type) { case PropertyType.DYNAMIC: { const dynamicProperty = property as DynamicProperties<boolean> const props = await dynamicProperty.props(resolvedInput, ctx) return { type: PropertyType.DYNAMIC, options: props, } } case PropertyType.MULTI_SELECT_DROPDOWN: { const multiSelectProperty = property as MultiSelectDropdownProperty< unknown, boolean > const options = await multiSelectProperty.options(resolvedInput, ctx) return { type: PropertyType.MULTI_SELECT_DROPDOWN, options, } } case PropertyType.DROPDOWN: { const dropdownProperty = property as DropdownProperty<unknown, boolean> const options = await dropdownProperty.options(resolvedInput, ctx) return { type: PropertyType.DROPDOWN, options, } } default: { throw new EngineGenericError('PropertyTypeNotExecutableError', `Property type is not executable: ${property}`) } } })) if (executePropsError) { console.error(executePropsError) return { type: property.type, options: { disabled: true, options: [], placeholder: 'Throws an error, reconnect or refresh the page', }, } } return executePropsResult }, async executeValidateAuth( { params, devPieces }: { params: ExecuteValidateAuthOperation, devPieces: string[] }, ): Promise<ExecuteValidateAuthResponse> { const { piece: piecePackage } = params const piece = await pieceLoader.loadPieceOrThrow({ pieceName: piecePackage.pieceName, pieceVersion: piecePackage.pieceVersion, devPieces }) const server = { apiUrl: params.internalApiUrl.endsWith('/') ? params.internalApiUrl : params.internalApiUrl + '/', publicUrl: params.publicApiUrl, } return validateAuth({ authValue: params.auth, pieceAuth: piece.auth, server, }) }, async extractPieceMetadata({ devPieces, params }: { devPieces: string[], params: ExecuteExtractPieceMetadata }): Promise<PieceMetadata> { const { pieceName, pieceVersion } = params const piece = await pieceLoader.loadPieceOrThrow({ pieceName, pieceVersion, devPieces }) const pieceAlias = pieceLoader.getPackageAlias({ pieceName, pieceVersion, devPieces }) const pieceFolderPath = await pieceLoader.getPiecePath({ packageName: pieceAlias, devPieces }) const i18n = await pieceTranslation.initializeI18n(pieceFolderPath) const fullMetadata = piece.metadata() return { ...fullMetadata, name: pieceName, version: pieceVersion, authors: piece.authors, i18n, } }, } type ExecutePropsParams = Omit<ExecutePropsOptions, 'piece'> & { pieceName: string, pieceVersion: string } function mismatchAuthTypeErrorMessage(pieceAuthType: PropertyType, connectionType: AppConnectionType): ExecuteValidateAuthResponse { return { valid: false, error: `Connection value type does not match piece auth type: ${pieceAuthType} !== ${connectionType}`, } } const validateAuth = async ({ server, authValue, pieceAuth, }: ValidateAuthParams): Promise<ExecuteValidateAuthResponse> => { if (isNil(pieceAuth)) { return { valid: true, } } const usedPieceAuth = getAuthPropertyForValue({ authValueType: authValue.type, pieceAuth, }) if (isNil(usedPieceAuth)) { return { valid: false, error: 'No piece auth found for auth value', } } if (isNil(usedPieceAuth.validate)) { return { valid: true, } } switch (usedPieceAuth.type) { case PropertyType.OAUTH2:{ if (authValue.type !== AppConnectionType.OAUTH2 && authValue.type !== AppConnectionType.CLOUD_OAUTH2 && authValue.type !== AppConnectionType.PLATFORM_OAUTH2) { return mismatchAuthTypeErrorMessage(usedPieceAuth.type, authValue.type) } return usedPieceAuth.validate({ auth: authValue, server, }) } case PropertyType.BASIC_AUTH:{ if (authValue.type !== AppConnectionType.BASIC_AUTH) { return mismatchAuthTypeErrorMessage(usedPieceAuth.type, authValue.type) } return usedPieceAuth.validate({ auth: authValue, server, }) } case PropertyType.SECRET_TEXT:{ if (authValue.type !== AppConnectionType.SECRET_TEXT) { return mismatchAuthTypeErrorMessage(usedPieceAuth.type, authValue.type) } return usedPieceAuth.validate({ auth: authValue.secret_text, server, }) } case PropertyType.CUSTOM_AUTH:{ if (authValue.type !== AppConnectionType.CUSTOM_AUTH) { return mismatchAuthTypeErrorMessage(usedPieceAuth.type, authValue.type) } return usedPieceAuth.validate({ auth: authValue.props, server, }) } default: { throw new EngineGenericError('InvalidAuthTypeError', 'Invalid auth type') } } } type ValidateAuthParams = { server: { apiUrl: string publicUrl: string } authValue: AppConnectionValue pieceAuth: PieceAuthProperty | PieceAuthProperty[] | undefined }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/activepieces/activepieces'

If you have feedback or need assistance with the MCP directory API, please join our Discord server