diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 11157fd15a9..51a4edcbe34 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -4617,6 +4617,7 @@ export type UpdateLogicFunctionInput = { }; export type UpdateLogicFunctionInputUpdates = { + builtHandlerPath?: InputMaybe; code: Scalars['JSON']; description?: InputMaybe; handlerName?: InputMaybe; diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index 702fe4a5bba..d38e6dc0c0d 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -4456,6 +4456,7 @@ export type UpdateLogicFunctionInput = { }; export type UpdateLogicFunctionInputUpdates = { + builtHandlerPath?: InputMaybe; code: Scalars['JSON']; description?: InputMaybe; handlerName?: InputMaybe; diff --git a/packages/twenty-server/src/engine/core-modules/application/services/application-sync.service.ts b/packages/twenty-server/src/engine/core-modules/application/services/application-sync.service.ts index 5cf8fd4f03a..f21dd130aca 100644 --- a/packages/twenty-server/src/engine/core-modules/application/services/application-sync.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/services/application-sync.service.ts @@ -3,16 +3,15 @@ import { Injectable, Logger } from '@nestjs/common'; import { parse } from 'path'; import { - Manifest, FieldManifest, LogicFunctionManifest, - LogicFunctionTriggerManifest, - ObjectManifest, - RoleManifest, + Manifest, ObjectFieldManifest, + ObjectManifest, RelationFieldManifest, + RoleManifest, } from 'twenty-shared/application'; -import { FieldMetadataType, HTTPMethod, Sources } from 'twenty-shared/types'; +import { FieldMetadataType, Sources } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; @@ -23,25 +22,20 @@ import { import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input'; import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; import { ApplicationVariableEntityService } from 'src/engine/core-modules/applicationVariable/application-variable.service'; +import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { findFlatEntitiesByApplicationId } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entities-by-application-id.util'; import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; +import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; +import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; import { FieldPermissionService } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.service'; import { ObjectPermissionService } from 'src/engine/metadata-modules/object-permission/object-permission.service'; import { PermissionFlagService } from 'src/engine/metadata-modules/permission-flag/permission-flag.service'; import { RoleService } from 'src/engine/metadata-modules/role/role.service'; -import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service'; -import { - CronTriggerSettings, - DatabaseEventTriggerSettings, - HttpRouteTriggerSettings, -} from 'src/engine/metadata-modules/logic-function/logic-function.entity'; -import { LogicFunctionV2Service } from 'src/engine/metadata-modules/logic-function/services/logic-function-v2.service'; -import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { computeMetadataNameFromLabelOrThrow } from 'src/engine/metadata-modules/utils/compute-metadata-name-from-label-or-throw.util'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @@ -55,7 +49,7 @@ export class ApplicationSyncService { private readonly logicFunctionLayerService: LogicFunctionLayerService, private readonly objectMetadataService: ObjectMetadataService, private readonly fieldMetadataService: FieldMetadataService, - private readonly logicFunctionV2Service: LogicFunctionV2Service, + private readonly logicFunctionService: LogicFunctionService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly dataSourceService: DataSourceService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, @@ -844,9 +838,10 @@ export class ApplicationSyncService { ); for (const logicFunctionToDelete of logicFunctionsToDelete) { - await this.logicFunctionV2Service.destroyOne({ - destroyLogicFunctionInput: { id: logicFunctionToDelete.id }, + await this.logicFunctionService.destroyOne({ + id: logicFunctionToDelete.id, workspaceId, + applicationId, isSystemBuild: true, }); } @@ -868,7 +863,7 @@ export class ApplicationSyncService { const name = logicFunctionToSync.name ?? parse(logicFunctionToSync.handlerName).name; - const updateLogicFunctionInput = { + await this.logicFunctionService.updateOne({ id: logicFunctionToUpdate.id, update: { name, @@ -880,12 +875,9 @@ export class ApplicationSyncService { toolInputSchema: logicFunctionToSync.toolInputSchema, isTool: logicFunctionToSync.isTool, }, - }; - - await this.logicFunctionV2Service.updateOne( - updateLogicFunctionInput, workspaceId, - ); + applicationId, + }); // Trigger settings are now embedded in the logic function entity // They are handled through the update input @@ -896,68 +888,25 @@ export class ApplicationSyncService { logicFunctionToCreate.name ?? parse(logicFunctionToCreate.handlerName).name; - const createLogicFunctionInput = { - name, - code, - universalIdentifier: logicFunctionToCreate.universalIdentifier, - timeoutSeconds: logicFunctionToCreate.timeoutSeconds, - sourceHandlerPath: logicFunctionToCreate.sourceHandlerPath, - handlerName: logicFunctionToCreate.handlerName, - builtHandlerPath: logicFunctionToCreate.builtHandlerPath, - applicationId, - logicFunctionLayerId, - toolInputSchema: logicFunctionToCreate.toolInputSchema, - isTool: logicFunctionToCreate.isTool, - }; - - await this.logicFunctionV2Service.createOne({ - createLogicFunctionInput, + await this.logicFunctionService.createOne({ + input: { + name, + code, + universalIdentifier: logicFunctionToCreate.universalIdentifier, + timeoutSeconds: logicFunctionToCreate.timeoutSeconds, + sourceHandlerPath: logicFunctionToCreate.sourceHandlerPath, + handlerName: logicFunctionToCreate.handlerName, + builtHandlerPath: logicFunctionToCreate.builtHandlerPath, + logicFunctionLayerId, + toolInputSchema: logicFunctionToCreate.toolInputSchema, + isTool: logicFunctionToCreate.isTool, + }, workspaceId, applicationId, }); - - // Trigger settings are now embedded in the logic function entity - // They are handled through the create input } } - private extractTriggerSettingsFromManifest( - triggers: LogicFunctionTriggerManifest[] = [], - ): { - cronTriggerSettings: CronTriggerSettings | null; - databaseEventTriggerSettings: DatabaseEventTriggerSettings | null; - httpRouteTriggerSettings: HttpRouteTriggerSettings | null; - } { - let cronTriggerSettings: CronTriggerSettings | null = null; - let databaseEventTriggerSettings: DatabaseEventTriggerSettings | null = - null; - let httpRouteTriggerSettings: HttpRouteTriggerSettings | null = null; - - for (const trigger of triggers) { - if (trigger.type === 'cron') { - cronTriggerSettings = { pattern: trigger.pattern }; - } else if (trigger.type === 'databaseEvent') { - databaseEventTriggerSettings = { - eventName: trigger.eventName, - updatedFields: trigger.updatedFields, - }; - } else if (trigger.type === 'route') { - httpRouteTriggerSettings = { - path: trigger.path, - httpMethod: trigger.httpMethod as HTTPMethod, - isAuthRequired: trigger.isAuthRequired, - forwardedRequestHeaders: trigger.forwardedRequestHeaders, - }; - } - } - - return { - cronTriggerSettings, - databaseEventTriggerSettings, - httpRouteTriggerSettings, - }; - } - public async uninstallApplication({ workspaceId, applicationUniversalIdentifier, diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module.ts index 3e0d900f691..aa0c9faf22f 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module.ts @@ -1,12 +1,15 @@ import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; import { AuditModule } from 'src/engine/core-modules/audit/audit.module'; import { TokenModule } from 'src/engine/core-modules/auth/token/token.module'; +import { FileModule } from 'src/engine/core-modules/file/file.module'; import { LogicFunctionBuildModule } from 'src/engine/core-modules/logic-function/logic-function-build/logic-function-build.module'; import { AddPackagesCommand } from 'src/engine/core-modules/logic-function/logic-function-executor/commands/add-packages.command'; import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { SecretEncryptionModule } from 'src/engine/core-modules/secret-encryption/secret-encryption.module'; import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.module'; +import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; @@ -19,6 +22,8 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache SubscriptionsModule, WorkspaceCacheModule, LogicFunctionBuildModule, + FileModule, + TypeOrmModule.forFeature([LogicFunctionEntity]), ], providers: [LogicFunctionExecutorService, AddPackagesCommand], exports: [LogicFunctionExecutorService], diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service.ts index 8109029c564..cbc4b485cf1 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service.ts @@ -1,28 +1,36 @@ import { Inject, Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; import { DEFAULT_API_KEY_NAME, DEFAULT_API_URL_NAME, } from 'twenty-shared/application'; +import { FileFolder } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; +import { Repository } from 'typeorm'; import { LogicFunctionExecutorDriver, type LogicFunctionExecuteParams, type LogicFunctionExecuteResult, } from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface'; +import { FileStorageExceptionCode } from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception'; import { AuditService } from 'src/engine/core-modules/audit/services/audit.service'; import { LOGIC_FUNCTION_EXECUTED_EVENT } from 'src/engine/core-modules/audit/utils/events/workspace-event/logic-function/logic-function-executed'; import { ApplicationTokenService } from 'src/engine/core-modules/auth/token/services/application-token.service'; +import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; import { LogicFunctionBuildService } from 'src/engine/core-modules/logic-function/logic-function-build/services/logic-function-build.service'; +import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util'; import { buildEnvVar } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/build-env-var'; import { LOGIC_FUNCTION_EXECUTOR_DRIVER } from 'src/engine/core-modules/logic-function/logic-function-executor/constants/logic-function-executor.constants'; import { SecretEncryptionService } from 'src/engine/core-modules/secret-encryption/secret-encryption.service'; import { ThrottlerService } from 'src/engine/core-modules/throttler/throttler.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; +import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; +import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; import { SubscriptionChannel } from 'src/engine/subscriptions/enums/subscription-channel.enum'; import { SubscriptionService } from 'src/engine/subscriptions/subscription.service'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; @@ -60,6 +68,9 @@ export class LogicFunctionExecutorService private readonly functionBuildService: LogicFunctionBuildService, private readonly subscriptionService: SubscriptionService, private readonly auditService: AuditService, + private readonly fileStorageService: FileStorageService, + @InjectRepository(LogicFunctionEntity) + private readonly logicFunctionRepository: Repository, ) {} async delete(flatLogicFunction: FlatLogicFunction): Promise { @@ -228,6 +239,84 @@ export class LogicFunctionExecutorService return resultLogicFunction; } + async getLogicFunctionSourceCode(workspaceId: string, id: string) { + try { + const { flatLogicFunctionMaps, flatApplicationMaps } = + await this.workspaceCacheService.getOrRecompute(workspaceId, [ + 'flatLogicFunctionMaps', + 'flatApplicationMaps', + ]); + + const flatLogicFunction = findFlatLogicFunctionOrThrow({ + id, + flatLogicFunctionMaps, + }); + + const applicationUniversalIdentifier = isDefined( + flatLogicFunction.applicationId, + ) + ? flatApplicationMaps.byId[flatLogicFunction.applicationId] + ?.universalIdentifier + : undefined; + + if (!isDefined(applicationUniversalIdentifier)) { + throw new LogicFunctionExecutionException( + `Application universal identifier not found for logic function ${id}`, + LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, + ); + } + + const baseFolderPath = getLogicFunctionBaseFolderPath( + flatLogicFunction.sourceHandlerPath, + ); + + return await this.fileStorageService.readFolder_v2({ + workspaceId, + applicationUniversalIdentifier, + fileFolder: FileFolder.Source, + resourcePath: baseFolderPath, + }); + } catch (error) { + if ( + isDefined(error) && + 'code' in error && + error.code === FileStorageExceptionCode.FILE_NOT_FOUND + ) { + return; + } + throw error; + } + } + + async getAvailablePackages(logicFunctionId: string) { + const logicFunction = await this.logicFunctionRepository.findOneOrFail({ + where: { id: logicFunctionId }, + relations: ['logicFunctionLayer'], + }); + + const packageJson = logicFunction.logicFunctionLayer.packageJson; + + const yarnLock = logicFunction.logicFunctionLayer.yarnLock; + + const packageVersionRegex = /^"([^@]+)@.*?":\n\s+version: (.+)$/gm; + + const versions: Record = {}; + + let match: RegExpExecArray | null; + + while ((match = packageVersionRegex.exec(yarnLock)) !== null) { + const packageName = match[1].split('@', 1)[0]; + const version = match[2]; + + // @ts-expect-error legacy noImplicitAny + if (packageJson.dependencies?.[packageName]) { + versions[packageName] = version; + } + } + + return versions; + } + private async throttleExecution(workspaceId: string) { try { await this.throttlerService.tokenBucketThrottleOrThrow( diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/providers/logic-function-tool.provider.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/providers/logic-function-tool.provider.ts index 39b4fc3cde5..6aa6b05620f 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/providers/logic-function-tool.provider.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/providers/logic-function-tool.provider.ts @@ -8,10 +8,10 @@ import { type ToolProviderContext, } from 'src/engine/core-modules/tool-provider/interfaces/tool-provider.interface'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { ToolCategory } from 'src/engine/core-modules/tool-provider/enums/tool-category.enum'; import { wrapJsonSchemaForExecution } from 'src/engine/core-modules/tool/utils/wrap-tool-for-execution.util'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; @Injectable() @@ -19,7 +19,7 @@ export class LogicFunctionToolProvider implements ToolProvider { readonly category = ToolCategory.LOGIC_FUNCTION; constructor( - private readonly logicFunctionService: LogicFunctionService, + private readonly logicFunctionExecutorService: LogicFunctionExecutorService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, ) {} @@ -63,7 +63,7 @@ export class LogicFunctionToolProvider implements ToolProvider { const { loadingMessage: _, ...actualParams } = parameters; const result = - await this.logicFunctionService.executeOneLogicFunction({ + await this.logicFunctionExecutorService.executeOneLogicFunction({ id: logicFunction.id, workspaceId: context.workspaceId, payload: actualParams, diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/update-logic-function.input.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/update-logic-function.input.ts index bb42397986f..d6372b0f416 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/update-logic-function.input.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/update-logic-function.input.ts @@ -52,6 +52,11 @@ class UpdateLogicFunctionInputUpdates { @IsOptional() sourceHandlerPath?: string; + @IsString() + @Field({ nullable: true }) + @IsOptional() + builtHandlerPath?: string; + @Field(() => graphqlTypeJson, { nullable: true }) @IsObject() @IsOptional() diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.module.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.module.ts index c207b1cf155..f3551034657 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.module.ts @@ -11,14 +11,15 @@ import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature- import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module'; import { FileModule } from 'src/engine/core-modules/file/file.module'; +import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; +import { CoreLogicFunctionLayerModule } from 'src/engine/core-modules/logic-function/logic-function-layer/logic-function-layer.module'; import { SecretEncryptionModule } from 'src/engine/core-modules/secret-encryption/secret-encryption.module'; import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module'; import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; import { LogicFunctionResolver } from 'src/engine/metadata-modules/logic-function/logic-function.resolver'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service'; -import { LogicFunctionV2Service } from 'src/engine/metadata-modules/logic-function/services/logic-function-v2.service'; +import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; import { WorkspaceFlatLogicFunctionMapCacheService } from 'src/engine/metadata-modules/logic-function/services/workspace-flat-logic-function-map-cache.service'; import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module'; @@ -39,6 +40,8 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace WorkspaceManyOrAllFlatEntityMapsCacheModule, WorkspaceMigrationModule, LogicFunctionLayerModule, + CoreLogicFunctionLayerModule, + LogicFunctionExecutorModule, SubscriptionsModule, WorkspaceCacheModule, TokenModule, @@ -46,10 +49,9 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace ], providers: [ LogicFunctionService, - LogicFunctionV2Service, LogicFunctionResolver, WorkspaceFlatLogicFunctionMapCacheService, ], - exports: [LogicFunctionService, LogicFunctionV2Service], + exports: [LogicFunctionService, LogicFunctionExecutorModule], }) export class LogicFunctionModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.resolver.ts index d11704c22c9..a61eeed2165 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.resolver.ts @@ -7,6 +7,7 @@ import { isDefined } from 'twenty-shared/utils'; import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter'; import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; import { FeatureFlagGuard } from 'src/engine/guards/feature-flag.guard'; @@ -22,7 +23,7 @@ import { LogicFunctionLogsDTO } from 'src/engine/metadata-modules/logic-function import { LogicFunctionLogsInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-logs.input'; import { LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto'; import { UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service'; +import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; import { fromFlatLogicFunctionToLogicFunctionDto } from 'src/engine/metadata-modules/logic-function/utils/from-flat-logic-function-to-logic-function-dto.util'; @@ -41,6 +42,7 @@ import { SubscriptionService } from 'src/engine/subscriptions/subscription.servi export class LogicFunctionResolver { constructor( private readonly logicFunctionService: LogicFunctionService, + private readonly logicFunctionExecutorService: LogicFunctionExecutorService, private readonly subscriptionService: SubscriptionService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, ) {} @@ -104,7 +106,7 @@ export class LogicFunctionResolver { @Query(() => graphqlTypeJson) async getAvailablePackages(@Args('input') { id }: LogicFunctionIdInput) { try { - return await this.logicFunctionService.getAvailablePackages(id); + return await this.logicFunctionExecutorService.getAvailablePackages(id); } catch (error) { return logicFunctionGraphQLApiExceptionHandler(error); } @@ -116,7 +118,7 @@ export class LogicFunctionResolver { @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, ) { try { - return await this.logicFunctionService.getLogicFunctionSourceCode( + return await this.logicFunctionExecutorService.getLogicFunctionSourceCode( workspaceId, input.id, ); @@ -132,11 +134,10 @@ export class LogicFunctionResolver { @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, ): Promise { try { - const flatLogicFunction = - await this.logicFunctionService.deleteOneLogicFunction({ - id: input.id, - workspaceId, - }); + const flatLogicFunction = await this.logicFunctionService.destroyOne({ + id: input.id, + workspaceId, + }); return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction, @@ -154,11 +155,11 @@ export class LogicFunctionResolver { @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, ): Promise { try { - const flatLogicFunction = - await this.logicFunctionService.updateOneLogicFunction( - input, - workspaceId, - ); + const flatLogicFunction = await this.logicFunctionService.updateOne({ + id: input.id, + update: input.update, + workspaceId, + }); return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction, @@ -176,11 +177,10 @@ export class LogicFunctionResolver { @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, ): Promise { try { - const flatLogicFunction = - await this.logicFunctionService.createOneLogicFunction( - input, - workspaceId, - ); + const flatLogicFunction = await this.logicFunctionService.createOne({ + input, + workspaceId, + }); return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction, @@ -199,7 +199,7 @@ export class LogicFunctionResolver { try { const { id, payload } = input; - return await this.logicFunctionService.executeOneLogicFunction({ + return await this.logicFunctionExecutorService.executeOneLogicFunction({ id, workspaceId, payload, diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.service.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.service.ts deleted file mode 100644 index 976470b48e0..00000000000 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.service.ts +++ /dev/null @@ -1,544 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; - -import { FileFolder } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; - -import { FileStorageExceptionCode } from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception'; -import { type LogicFunctionExecuteResult } from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface'; - -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; -import { LogicFunctionBuildService } from 'src/engine/core-modules/logic-function/logic-function-build/services/logic-function-build.service'; -import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util'; -import { - LogicFunctionExecutionException, - LogicFunctionExecutionExceptionCode, - LogicFunctionExecutorService, -} from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; -import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service'; -import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; -import { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input'; -import { type UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input'; -import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; -import { - LogicFunctionException, - LogicFunctionExceptionCode, -} from 'src/engine/metadata-modules/logic-function/logic-function.exception'; -import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; -import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; -import { fromCreateLogicFunctionInputToFlatLogicFunction } from 'src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util'; -import { fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow } from 'src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; -import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; - -@Injectable() -export class LogicFunctionService { - constructor( - private readonly fileStorageService: FileStorageService, - private readonly functionBuildService: LogicFunctionBuildService, - private readonly logicFunctionLayerService: LogicFunctionLayerService, - private readonly logicFunctionExecutorService: LogicFunctionExecutorService, - @InjectRepository(LogicFunctionEntity) - private readonly logicFunctionRepository: Repository, - private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, - private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, - private readonly applicationService: ApplicationService, - private readonly workspaceCacheService: WorkspaceCacheService, - ) {} - - async getLogicFunctionSourceCode(workspaceId: string, id: string) { - try { - const { flatLogicFunctionMaps, flatApplicationMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatLogicFunctionMaps', - 'flatApplicationMaps', - ]); - - const flatLogicFunction = findFlatLogicFunctionOrThrow({ - id, - flatLogicFunctionMaps, - }); - - const applicationUniversalIdentifier = isDefined( - flatLogicFunction.applicationId, - ) - ? flatApplicationMaps.byId[flatLogicFunction.applicationId] - ?.universalIdentifier - : undefined; - - if (!isDefined(applicationUniversalIdentifier)) { - throw new LogicFunctionException( - `Application universal identifier not found for logic function ${id}`, - LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - const baseFolderPath = getLogicFunctionBaseFolderPath( - flatLogicFunction.sourceHandlerPath, - ); - - return await this.fileStorageService.readFolder_v2({ - workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Source, - resourcePath: baseFolderPath, - }); - } catch (error) { - if (error.code === FileStorageExceptionCode.FILE_NOT_FOUND) { - return; - } - throw error; - } - } - - async executeOneLogicFunction({ - id, - workspaceId, - payload, - }: { - id: string; - workspaceId: string; - payload: object; - }): Promise { - try { - return await this.logicFunctionExecutorService.executeOneLogicFunction({ - id, - workspaceId, - payload, - }); - } catch (error) { - if (error instanceof LogicFunctionExecutionException) { - switch (error.code) { - case LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND: - throw new LogicFunctionException( - error.message, - LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - case LogicFunctionExecutionExceptionCode.RATE_LIMIT_EXCEEDED: - throw new LogicFunctionException( - error.message, - LogicFunctionExceptionCode.LOGIC_FUNCTION_EXECUTION_LIMIT_REACHED, - ); - } - } - throw error; - } - } - - async deleteOneLogicFunction({ - id, - workspaceId, - softDelete = false, - }: { - id: string; - workspaceId: string; - softDelete?: boolean; - }): Promise { - const { flatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - const existingFlatLogicFunction = flatLogicFunctionMaps.byId[id]; - - if (!isDefined(existingFlatLogicFunction)) { - throw new LogicFunctionException( - 'Logic function to delete not found', - LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - if (softDelete) { - const updatedFlatLogicFunctionWithDeletedAt: FlatLogicFunction = { - ...existingFlatLogicFunction, - deletedAt: new Date().toISOString(), - }; - - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - logicFunction: { - flatEntityToCreate: [], - flatEntityToDelete: [], - flatEntityToUpdate: [updatedFlatLogicFunctionWithDeletedAt], - }, - }, - workspaceId, - isSystemBuild: false, - }, - ); - - if (isDefined(validateAndBuildResult)) { - throw new WorkspaceMigrationBuilderException( - validateAndBuildResult, - 'Multiple validation errors occurred while deleting logic function', - ); - } - - return updatedFlatLogicFunctionWithDeletedAt; - } else { - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - logicFunction: { - flatEntityToCreate: [], - flatEntityToDelete: [existingFlatLogicFunction], - flatEntityToUpdate: [], - }, - }, - workspaceId, - isSystemBuild: false, - }, - ); - - if (isDefined(validateAndBuildResult)) { - throw new WorkspaceMigrationBuilderException( - validateAndBuildResult, - 'Multiple validation errors occurred while destroying logic function', - ); - } - } - - return existingFlatLogicFunction; - } - - async restoreOneLogicFunction( - id: string, - workspaceId: string, - ): Promise { - const { flatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - const existingFlatLogicFunction = flatLogicFunctionMaps.byId[id]; - - if (!isDefined(existingFlatLogicFunction)) { - throw new LogicFunctionException( - 'Logic function to restore not found', - LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - const restoredFlatLogicFunction: FlatLogicFunction = { - ...existingFlatLogicFunction, - deletedAt: null, - }; - - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - logicFunction: { - flatEntityToCreate: [], - flatEntityToDelete: [], - flatEntityToUpdate: [restoredFlatLogicFunction], - }, - }, - workspaceId, - isSystemBuild: false, - }, - ); - - if (isDefined(validateAndBuildResult)) { - throw new WorkspaceMigrationBuilderException( - validateAndBuildResult, - 'Multiple validation errors occurred while restoring logic function', - ); - } - - const { flatLogicFunctionMaps: recomputedFlatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - return findFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityId: id, - flatEntityMaps: recomputedFlatLogicFunctionMaps, - }); - } - - async updateOneLogicFunction( - logicFunctionInput: UpdateLogicFunctionInput, - workspaceId: string, - ): Promise { - const { flatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - const updatedFlatLogicFunction = - fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow({ - flatLogicFunctionMaps, - updateLogicFunctionInput: logicFunctionInput, - }); - - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - logicFunction: { - flatEntityToCreate: [], - flatEntityToDelete: [], - flatEntityToUpdate: [updatedFlatLogicFunction], - }, - }, - workspaceId, - isSystemBuild: false, - }, - ); - - if (isDefined(validateAndBuildResult)) { - throw new WorkspaceMigrationBuilderException( - validateAndBuildResult, - 'Multiple validation errors occurred while updating logic function', - ); - } - - const { flatLogicFunctionMaps: recomputedFlatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - return findFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityId: updatedFlatLogicFunction.id, - flatEntityMaps: recomputedFlatLogicFunctionMaps, - }); - } - - async getAvailablePackages(logicFunctionId: string) { - const logicFunction = await this.logicFunctionRepository.findOneOrFail({ - where: { id: logicFunctionId }, - relations: ['logicFunctionLayer'], - }); - - const packageJson = logicFunction.logicFunctionLayer.packageJson; - - const yarnLock = logicFunction.logicFunctionLayer.yarnLock; - - const packageVersionRegex = /^"([^@]+)@.*?":\n\s+version: (.+)$/gm; - - const versions: Record = {}; - - let match: RegExpExecArray | null; - - while ((match = packageVersionRegex.exec(yarnLock)) !== null) { - const packageName = match[1].split('@', 1)[0]; - const version = match[2]; - - // @ts-expect-error legacy noImplicitAny - if (packageJson.dependencies?.[packageName]) { - versions[packageName] = version; - } - } - - return versions; - } - - async createOneLogicFunction( - logicFunctionInput: CreateLogicFunctionInput & { - logicFunctionLayerId?: string; - }, - workspaceId: string, - ): Promise { - let logicFunctionToCreateLayerId = logicFunctionInput.logicFunctionLayerId; - - if (!isDefined(logicFunctionToCreateLayerId)) { - const { id: commonLogicFunctionLayerId } = - await this.logicFunctionLayerService.createCommonLayerIfNotExist( - workspaceId, - ); - - logicFunctionToCreateLayerId = commonLogicFunctionLayerId; - } - - const { workspaceCustomFlatApplication } = - await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { - workspaceId, - }, - ); - - const flatLogicFunctionToCreate = - fromCreateLogicFunctionInputToFlatLogicFunction({ - createLogicFunctionInput: { - ...logicFunctionInput, - logicFunctionLayerId: logicFunctionToCreateLayerId, - }, - workspaceId, - workspaceCustomApplicationId: - logicFunctionInput.applicationId ?? workspaceCustomFlatApplication.id, - }); - - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - logicFunction: { - flatEntityToCreate: [flatLogicFunctionToCreate], - flatEntityToDelete: [], - flatEntityToUpdate: [], - }, - }, - workspaceId, - isSystemBuild: false, - }, - ); - - if (isDefined(validateAndBuildResult)) { - throw new WorkspaceMigrationBuilderException( - validateAndBuildResult, - 'Multiple validation errors occurred while creating logic function', - ); - } - - const { flatLogicFunctionMaps: recomputedFlatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - return findFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityId: flatLogicFunctionToCreate.id, - flatEntityMaps: recomputedFlatLogicFunctionMaps, - }); - } - - async duplicateLogicFunction({ - id, - workspaceId, - }: { - id: string; - workspaceId: string; - }): Promise { - return this.createLogicFunctionFromExistingLogicFunctionById({ - id, - workspaceId, - }); - } - - async createLogicFunctionFromExistingLogicFunctionById({ - id, - workspaceId, - }: { - id: string; - workspaceId: string; - }): Promise { - const { flatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - const existingLogicFunction = findFlatLogicFunctionOrThrow({ - id, - flatLogicFunctionMaps, - }); - - return this.createLogicFunctionFromExistingLogicFunction({ - existingLogicFunction, - workspaceId, - }); - } - - async createLogicFunctionFromExistingLogicFunction({ - existingLogicFunction, - workspaceId, - }: { - existingLogicFunction: FlatLogicFunction; - workspaceId: string; - }): Promise { - const { flatApplicationMaps } = - await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatApplicationMaps', - ]); - - const existingApplicationUniversalIdentifier = isDefined( - existingLogicFunction.applicationId, - ) - ? flatApplicationMaps.byId[existingLogicFunction.applicationId] - ?.universalIdentifier - : undefined; - - if (!isDefined(existingApplicationUniversalIdentifier)) { - throw new LogicFunctionException( - `Application universal identifier not found for logic function ${existingLogicFunction.id}`, - LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - const newFlatLogicFunction = await this.createOneLogicFunction( - { - name: existingLogicFunction.name, - description: existingLogicFunction.description ?? undefined, - timeoutSeconds: existingLogicFunction.timeoutSeconds, - applicationId: existingLogicFunction.applicationId ?? undefined, - logicFunctionLayerId: existingLogicFunction.logicFunctionLayerId, - }, - workspaceId, - ); - - const newApplicationUniversalIdentifier = isDefined( - newFlatLogicFunction.applicationId, - ) - ? flatApplicationMaps.byId[newFlatLogicFunction.applicationId] - ?.universalIdentifier - : undefined; - - if (!isDefined(newApplicationUniversalIdentifier)) { - throw new LogicFunctionException( - `Application universal identifier not found for logic function ${newFlatLogicFunction.id}`, - LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - const fromBaseFolderPath = getLogicFunctionBaseFolderPath( - existingLogicFunction.sourceHandlerPath, - ); - const toBaseFolderPath = getLogicFunctionBaseFolderPath( - newFlatLogicFunction.sourceHandlerPath, - ); - - await this.fileStorageService.copy_v2({ - from: { - workspaceId, - applicationUniversalIdentifier: existingApplicationUniversalIdentifier, - fileFolder: FileFolder.Source, - resourcePath: fromBaseFolderPath, - }, - to: { - workspaceId, - applicationUniversalIdentifier: newApplicationUniversalIdentifier, - fileFolder: FileFolder.Source, - resourcePath: toBaseFolderPath, - }, - }); - - return newFlatLogicFunction; - } -} diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function-v2.service.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function.service.ts similarity index 58% rename from packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function-v2.service.ts rename to packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function.service.ts index 1f0024b2d20..f807d434f56 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function-v2.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function.service.ts @@ -1,46 +1,61 @@ import { Injectable } from '@nestjs/common'; +import { FileFolder } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; +import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; +import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util'; +import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; import type { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input'; -import { LogicFunctionIdInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-id.input'; -import { UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input'; +import type { UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input'; import { LogicFunctionException, LogicFunctionExceptionCode, } from 'src/engine/metadata-modules/logic-function/logic-function.exception'; import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; +import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; import { fromCreateLogicFunctionInputToFlatLogicFunction } from 'src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util'; import { fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow } from 'src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util'; +import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @Injectable() -export class LogicFunctionV2Service { +export class LogicFunctionService { constructor( private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly applicationService: ApplicationService, + private readonly logicFunctionLayerService: LogicFunctionLayerService, + private readonly workspaceCacheService: WorkspaceCacheService, + private readonly fileStorageService: FileStorageService, ) {} async createOne({ - createLogicFunctionInput, + input, workspaceId, applicationId, }: { - createLogicFunctionInput: CreateLogicFunctionInput & { - logicFunctionLayerId: string; + input: Omit & { + logicFunctionLayerId?: string; }; - /** - * @deprecated do not use call validateBuildAndRunWorkspaceMigration contextually - * when interacting with another application than workspace custom one - * */ - applicationId?: string; workspaceId: string; + applicationId?: string; }) { + let logicFunctionToCreateLayerId = input.logicFunctionLayerId; + + if (!isDefined(logicFunctionToCreateLayerId)) { + const { id: commonLogicFunctionLayerId } = + await this.logicFunctionLayerService.createCommonLayerIfNotExist( + workspaceId, + ); + + logicFunctionToCreateLayerId = commonLogicFunctionLayerId; + } + const { workspaceCustomFlatApplication } = await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( { @@ -50,7 +65,10 @@ export class LogicFunctionV2Service { const flatLogicFunctionToCreate = fromCreateLogicFunctionInputToFlatLogicFunction({ - createLogicFunctionInput, + createLogicFunctionInput: { + ...input, + logicFunctionLayerId: logicFunctionToCreateLayerId, + }, workspaceId, workspaceCustomApplicationId: applicationId ?? workspaceCustomFlatApplication.id, @@ -92,10 +110,17 @@ export class LogicFunctionV2Service { }); } - async updateOne( - logicFunctionInput: UpdateLogicFunctionInput, - workspaceId: string, - ) { + async updateOne({ + id, + update, + workspaceId, + applicationId: _applicationId, + }: { + id: string; + update: UpdateLogicFunctionInput['update']; + workspaceId: string; + applicationId?: string; + }) { const { flatLogicFunctionMaps } = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( { @@ -107,7 +132,7 @@ export class LogicFunctionV2Service { const optimisticallyUpdatedFlatLogicFunction = fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow({ flatLogicFunctionMaps, - updateLogicFunctionInput: logicFunctionInput, + updateLogicFunctionInput: { id, update }, }); const validateAndBuildResult = @@ -146,83 +171,15 @@ export class LogicFunctionV2Service { }); } - async deleteOne({ - deleteLogicFunctionInput, - workspaceId, - isSystemBuild = false, - }: { - deleteLogicFunctionInput: LogicFunctionIdInput; - workspaceId: string; - isSystemBuild?: boolean; - }): Promise { - const { flatLogicFunctionMaps: existingFlatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - const existingFlatLogicFunction = - existingFlatLogicFunctionMaps.byId[deleteLogicFunctionInput.id]; - - if (!isDefined(existingFlatLogicFunction)) { - throw new LogicFunctionException( - 'Logic function to delete not found', - LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - const optimisticallyUpdatedFlatLogicFunctionWithDeletedAt = { - ...existingFlatLogicFunction, - deletedAt: new Date().toISOString(), - }; - - const validateAndBuildResult = - await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( - { - allFlatEntityOperationByMetadataName: { - logicFunction: { - flatEntityToCreate: [], - flatEntityToDelete: [], - flatEntityToUpdate: [ - optimisticallyUpdatedFlatLogicFunctionWithDeletedAt, - ], - }, - }, - workspaceId, - isSystemBuild, - }, - ); - - if (isDefined(validateAndBuildResult)) { - throw new WorkspaceMigrationBuilderException( - validateAndBuildResult, - 'Multiple validation errors occurred while deleting logic function', - ); - } - - const { flatLogicFunctionMaps: recomputedExistingFlatLogicFunctionMaps } = - await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( - { - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }, - ); - - return findFlatEntityByIdInFlatEntityMapsOrThrow({ - flatEntityId: optimisticallyUpdatedFlatLogicFunctionWithDeletedAt.id, - flatEntityMaps: recomputedExistingFlatLogicFunctionMaps, - }); - } - async destroyOne({ - destroyLogicFunctionInput, + id, workspaceId, + applicationId: _applicationId, isSystemBuild = false, }: { - destroyLogicFunctionInput: LogicFunctionIdInput; + id: string; workspaceId: string; + applicationId?: string; isSystemBuild?: boolean; }): Promise { const { flatLogicFunctionMaps: existingFlatLogicFunctionMaps } = @@ -233,8 +190,7 @@ export class LogicFunctionV2Service { }, ); - const existingFlatLogicFunction = - existingFlatLogicFunctionMaps.byId[destroyLogicFunctionInput.id]; + const existingFlatLogicFunction = existingFlatLogicFunctionMaps.byId[id]; if (!isDefined(existingFlatLogicFunction)) { throw new LogicFunctionException( @@ -267,4 +223,119 @@ export class LogicFunctionV2Service { return existingFlatLogicFunction; } + + async duplicateLogicFunction({ + id, + workspaceId, + }: { + id: string; + workspaceId: string; + }): Promise { + return this.createLogicFunctionFromExistingLogicFunctionById({ + id, + workspaceId, + }); + } + + async createLogicFunctionFromExistingLogicFunctionById({ + id, + workspaceId, + }: { + id: string; + workspaceId: string; + }): Promise { + const { flatLogicFunctionMaps } = + await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( + { + workspaceId, + flatMapsKeys: ['flatLogicFunctionMaps'], + }, + ); + + const existingLogicFunction = findFlatLogicFunctionOrThrow({ + id, + flatLogicFunctionMaps, + }); + + return this.createLogicFunctionFromExistingLogicFunction({ + existingLogicFunction, + workspaceId, + }); + } + + async createLogicFunctionFromExistingLogicFunction({ + existingLogicFunction, + workspaceId, + }: { + existingLogicFunction: FlatLogicFunction; + workspaceId: string; + }): Promise { + const { flatApplicationMaps } = + await this.workspaceCacheService.getOrRecompute(workspaceId, [ + 'flatApplicationMaps', + ]); + + const existingApplicationUniversalIdentifier = isDefined( + existingLogicFunction.applicationId, + ) + ? flatApplicationMaps.byId[existingLogicFunction.applicationId] + ?.universalIdentifier + : undefined; + + if (!isDefined(existingApplicationUniversalIdentifier)) { + throw new LogicFunctionException( + `Application universal identifier not found for logic function ${existingLogicFunction.id}`, + LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, + ); + } + + const newFlatLogicFunction = await this.createOne({ + input: { + name: existingLogicFunction.name, + description: existingLogicFunction.description ?? undefined, + timeoutSeconds: existingLogicFunction.timeoutSeconds, + logicFunctionLayerId: existingLogicFunction.logicFunctionLayerId, + }, + workspaceId, + applicationId: existingLogicFunction.applicationId ?? undefined, + }); + + const newApplicationUniversalIdentifier = isDefined( + newFlatLogicFunction.applicationId, + ) + ? flatApplicationMaps.byId[newFlatLogicFunction.applicationId] + ?.universalIdentifier + : undefined; + + if (!isDefined(newApplicationUniversalIdentifier)) { + throw new LogicFunctionException( + `Application universal identifier not found for logic function ${newFlatLogicFunction.id}`, + LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, + ); + } + + const fromBaseFolderPath = getLogicFunctionBaseFolderPath( + existingLogicFunction.sourceHandlerPath, + ); + const toBaseFolderPath = getLogicFunctionBaseFolderPath( + newFlatLogicFunction.sourceHandlerPath, + ); + + await this.fileStorageService.copy_v2({ + from: { + workspaceId, + applicationUniversalIdentifier: existingApplicationUniversalIdentifier, + fileFolder: FileFolder.Source, + resourcePath: fromBaseFolderPath, + }, + to: { + workspaceId, + applicationUniversalIdentifier: newApplicationUniversalIdentifier, + fileFolder: FileFolder.Source, + resourcePath: toBaseFolderPath, + }, + }); + + return newFlatLogicFunction; + } } diff --git a/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-common.workspace-service.ts b/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-common.workspace-service.ts index c9be6449d83..35c9da06d2a 100644 --- a/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-common.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-common.workspace-service.ts @@ -7,7 +7,7 @@ import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/typ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service'; +import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { type WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; @@ -303,6 +303,11 @@ export class WorkflowCommonWorkspaceService { workspaceId: string; operation: 'restore' | 'delete' | 'destroy'; }) { + // Only handle destroy operation - soft delete/restore is no longer supported + if (operation !== 'destroy') { + return; + } + const workflowVersions = await workflowVersionRepository.find({ where: { workflowId, @@ -310,33 +315,15 @@ export class WorkflowCommonWorkspaceService { withDeleted: true, }); - workflowVersions.forEach((workflowVersion) => { - workflowVersion.steps?.forEach(async (step) => { + for (const workflowVersion of workflowVersions) { + for (const step of workflowVersion.steps ?? []) { if (step.type === WorkflowActionType.CODE) { - switch (operation) { - case 'delete': - await this.logicFunctionService.deleteOneLogicFunction({ - id: step.settings.input.logicFunctionId, - workspaceId, - softDelete: true, - }); - break; - case 'restore': - await this.logicFunctionService.restoreOneLogicFunction( - step.settings.input.logicFunctionId, - workspaceId, - ); - break; - case 'destroy': - await this.logicFunctionService.deleteOneLogicFunction({ - id: step.settings.input.logicFunctionId, - workspaceId, - softDelete: false, - }); - break; - } + await this.logicFunctionService.destroyOne({ + id: step.settings.input.logicFunctionId, + workspaceId, + }); } - }); - }); + } + } } } diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts index 363e1628697..fd6768fe4c0 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts @@ -6,7 +6,7 @@ import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/ag import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { LogicFunctionRuntime } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service'; +import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; @@ -36,8 +36,8 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { beforeEach(async () => { logicFunctionService = { - createOneLogicFunction: jest.fn(), - deleteOneLogicFunction: jest.fn(), + createOne: jest.fn(), + destroyOne: jest.fn(), duplicateLogicFunction: jest.fn(), } as unknown as jest.Mocked; @@ -154,10 +154,9 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { workspaceId: mockWorkspaceId, }); - expect(logicFunctionService.deleteOneLogicFunction).toHaveBeenCalledWith({ + expect(logicFunctionService.destroyOne).toHaveBeenCalledWith({ id: 'function-id', workspaceId: mockWorkspaceId, - softDelete: false, }); }); @@ -265,9 +264,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { httpRouteTriggerSettings: null, }; - logicFunctionService.createOneLogicFunction.mockResolvedValue( - mockFlatLogicFunction, - ); + logicFunctionService.createOne.mockResolvedValue(mockFlatLogicFunction); const result = await service.runStepCreationSideEffectsAndBuildStep({ type: WorkflowActionType.CODE, diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts index 05d60bef6f1..d96069d5a0d 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts @@ -21,7 +21,7 @@ import { AiAgentRoleService } from 'src/engine/metadata-modules/ai/ai-agent-role import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity'; import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service'; +import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; @@ -86,10 +86,9 @@ export class WorkflowVersionStepOperationsWorkspaceService { }) { switch (step.type) { case WorkflowActionType.CODE: { - await this.logicFunctionService.deleteOneLogicFunction({ + await this.logicFunctionService.destroyOne({ id: step.settings.input.logicFunctionId, workspaceId, - softDelete: false, }); break; } @@ -152,14 +151,13 @@ export class WorkflowVersionStepOperationsWorkspaceService { switch (type) { case WorkflowActionType.CODE: { - const newLogicFunction = - await this.logicFunctionService.createOneLogicFunction( - { - name: 'A Logic Function Code Workflow Step', - description: '', - }, - workspaceId, - ); + const newLogicFunction = await this.logicFunctionService.createOne({ + input: { + name: 'A Logic Function Code Workflow Step', + description: '', + }, + workspaceId, + }); if (!isDefined(newLogicFunction)) { throw new WorkflowVersionStepException( diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts index 064798702a7..95b1147705b 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts @@ -1,10 +1,10 @@ import { Module } from '@nestjs/common'; -import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module'; +import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; import { CodeWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action'; @Module({ - imports: [LogicFunctionModule], + imports: [LogicFunctionExecutorModule], providers: [CodeWorkflowAction], exports: [CodeWorkflowAction], }) diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts index 97f20a0523d..9456c133b23 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts @@ -4,7 +4,7 @@ import { resolveInput } from 'twenty-shared/utils'; import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { WorkflowStepExecutorException, WorkflowStepExecutorExceptionCode, @@ -17,7 +17,9 @@ import { type WorkflowCodeActionInput } from 'src/modules/workflow/workflow-exec @Injectable() export class CodeWorkflowAction implements WorkflowAction { - constructor(private readonly logicFunctionService: LogicFunctionService) {} + constructor( + private readonly logicFunctionExecutorService: LogicFunctionExecutorService, + ) {} async execute({ currentStepId, @@ -45,11 +47,12 @@ export class CodeWorkflowAction implements WorkflowAction { try { const { workspaceId } = runInfo; - const result = await this.logicFunctionService.executeOneLogicFunction({ - id: workflowActionInput.logicFunctionId, - workspaceId, - payload: workflowActionInput.logicFunctionInput, - }); + const result = + await this.logicFunctionExecutorService.executeOneLogicFunction({ + id: workflowActionInput.logicFunctionId, + workspaceId, + payload: workflowActionInput.logicFunctionInput, + }); if (result.error) { return { error: result.error.errorMessage }; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function-action.module.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function-action.module.ts index c00d83a0755..973416b27bd 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function-action.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function-action.module.ts @@ -1,11 +1,14 @@ import { Module } from '@nestjs/common'; +import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; -import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module'; import { LogicFunctionWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action'; @Module({ - imports: [LogicFunctionModule, WorkspaceManyOrAllFlatEntityMapsCacheModule], + imports: [ + LogicFunctionExecutorModule, + WorkspaceManyOrAllFlatEntityMapsCacheModule, + ], providers: [LogicFunctionWorkflowAction], exports: [LogicFunctionWorkflowAction], }) diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action.ts index 882d077a9d6..6e1de83ec75 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action.ts @@ -4,8 +4,8 @@ import { resolveInput } from 'twenty-shared/utils'; import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service'; import { WorkflowStepExecutorException, WorkflowStepExecutorExceptionCode, @@ -19,7 +19,7 @@ import { WorkflowLogicFunctionActionInput } from 'src/modules/workflow/workflow- @Injectable() export class LogicFunctionWorkflowAction implements WorkflowAction { constructor( - private readonly logicFunctionService: LogicFunctionService, + private readonly logicFunctionExecutorService: LogicFunctionExecutorService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, ) {} @@ -67,11 +67,12 @@ export class LogicFunctionWorkflowAction implements WorkflowAction { ); } - const result = await this.logicFunctionService.executeOneLogicFunction({ - id: workflowActionInput.logicFunctionId, - workspaceId, - payload: workflowActionInput.logicFunctionInput, - }); + const result = + await this.logicFunctionExecutorService.executeOneLogicFunction({ + id: workflowActionInput.logicFunctionId, + workspaceId, + payload: workflowActionInput.logicFunctionInput, + }); if (result.error) { return { error: result.error.errorMessage };