Rework logic function module (#17588)

core-modules/logic-function/
├── logic-function.module.ts
├── logic-function-executor/
│   ├── logic-function-executor.module.ts
│   ├── commands/
│   │   └── add-packages.command.ts
│   ├── constants/
│   │   └── logic-function-executor.constants.ts
│   ├── factories/
│   │   └── logic-function-module.factory.ts
│   ├── interfaces/
│   │   └── logic-function-executor.interface.ts
│   └── services/
│       └── logic-function-executor.service.ts
├── logic-function-build/
│   ├── logic-function-build.module.ts
│   ├── services/
│   │   └── logic-function-build.service.ts
│   └── utils/
│       └── get-logic-function-base-folder-path.util.ts
├── logic-function-drivers/
│   ├── logic-function-drivers.module.ts
│   ├── constants/
│   │   └── ...
│   ├── drivers/
│   │   ├── disabled.driver.ts
│   │   ├── lambda.driver.ts
│   │   └── local.driver.ts
│   ├── interfaces/
│   │   └── logic-function-executor-driver.interface.ts
│   ├── layers/
│   │   └── ...
│   └── utils/
│       └── ...
├── logic-function-layer/
│   ├── logic-function-layer.module.ts
│   └── services/
│       └── logic-function-layer.service.ts
└── logic-function-trigger/
    ├── logic-function-trigger.module.ts
    ├── jobs/
    │   └── logic-function-trigger.job.ts
    └── triggers/
        ├── cron/
        ├── database-event/
        └── route/
            ├── exceptions/
            ├── services/
            │   └── route-trigger.service.ts
            └── utils/
This commit is contained in:
Charles Bochet
2026-01-30 19:28:20 +01:00
committed by GitHub
parent cb5e5e4622
commit 4a770eafa1
73 changed files with 497 additions and 409 deletions
+5 -5
View File
@@ -11,23 +11,23 @@
"watchAssets": true,
"assets": [
{
"include": "engine/core-modules/logic-function-executor/drivers/constants/seed-project/**",
"include": "engine/core-modules/logic-function/logic-function-drivers/constants/seed-project/**",
"outDir": "dist/assets"
},
{
"include": "engine/core-modules/logic-function-executor/drivers/layers/*/package.json",
"include": "engine/core-modules/logic-function/logic-function-drivers/layers/*/package.json",
"outDir": "dist/assets"
},
{
"include": "engine/core-modules/logic-function-executor/drivers/layers/*/yarn.lock",
"include": "engine/core-modules/logic-function/logic-function-drivers/layers/*/yarn.lock",
"outDir": "dist/assets"
},
{
"include": "engine/core-modules/logic-function-executor/drivers/layers/engine/**",
"include": "engine/core-modules/logic-function/logic-function-drivers/layers/engine/**",
"outDir": "dist/assets"
},
{
"include": "engine/core-modules/logic-function-executor/drivers/constants/executor/index.mjs",
"include": "engine/core-modules/logic-function/logic-function-drivers/constants/executor/index.mjs",
"outDir": "dist/assets"
},
{
@@ -4,7 +4,7 @@ import { Command, CommandRunner } from 'nest-commander';
import { CheckPublicDomainsValidRecordsCronCommand } from 'src/engine/core-modules/public-domain/crons/commands/check-public-domains-valid-records.cron.command';
import { CheckCustomDomainValidRecordsCronCommand } from 'src/engine/core-modules/workspace/crons/commands/check-custom-domain-valid-records.cron.command';
import { CronTriggerCronCommand } from 'src/engine/metadata-modules/cron-trigger/crons/commands/cron-trigger.cron.command';
import { CronTriggerCronCommand } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/cron/cron-trigger.cron.command';
import { TrashCleanupCronCommand } from 'src/engine/trash-cleanup/commands/trash-cleanup.cron.command';
import { CleanOnboardingWorkspacesCronCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/clean-onboarding-workspaces.cron.command';
import { CleanSuspendedWorkspacesCronCommand } from 'src/engine/workspace-manager/workspace-cleaner/commands/clean-suspended-workspaces.cron.command';
@@ -14,9 +14,7 @@ import { FileModule } from 'src/engine/core-modules/file/file.module';
import { PublicDomainModule } from 'src/engine/core-modules/public-domain/public-domain.module';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
import { CronTriggerModule } from 'src/engine/metadata-modules/cron-trigger/cron-trigger.module';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { DatabaseEventTriggerModule } from 'src/engine/metadata-modules/database-event-trigger/database-event-trigger.module';
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { TrashCleanupModule } from 'src/engine/trash-cleanup/trash-cleanup.module';
@@ -51,8 +49,6 @@ import { AutomatedTriggerModule } from 'src/modules/workflow/workflow-trigger/au
WorkspaceCacheStorageModule,
ApiKeyModule,
FeatureFlagModule,
CronTriggerModule,
DatabaseEventTriggerModule,
WorkspaceCleanerModule,
WorkspaceMigrationModule,
TrashCleanupModule,
@@ -18,7 +18,7 @@ import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queu
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
import { CallWebhookJobsJob } from 'src/engine/metadata-modules/webhook/jobs/call-webhook-jobs.job';
import { WorkspaceEventBatchForWebhook } from 'src/engine/metadata-modules/webhook/types/workspace-event-batch-for-webhook.type';
import { CallDatabaseEventTriggerJobsJob } from 'src/engine/metadata-modules/database-event-trigger/jobs/call-database-event-trigger-jobs.job';
import { CallDatabaseEventTriggerJobsJob } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/database-event/call-database-event-trigger-jobs.job';
import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event-batch.type';
import { WorkspaceEventEmitterService } from 'src/engine/workspace-event-emitter/workspace-event-emitter.service';
import { UpsertTimelineActivityFromInternalEvent } from 'src/modules/timeline/jobs/upsert-timeline-activity-from-internal-event.job';
@@ -34,7 +34,7 @@ import { FieldPermissionService } from 'src/engine/metadata-modules/object-permi
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/metadata-modules/logic-function-layer/logic-function-layer.service';
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
import {
CronTriggerSettings,
DatabaseEventTriggerSettings,
@@ -47,8 +47,8 @@ import { PublicDomainModule } from 'src/engine/core-modules/public-domain/public
import { RedisClientModule } from 'src/engine/core-modules/redis-client/redis-client.module';
import { RedisClientService } from 'src/engine/core-modules/redis-client/redis-client.service';
import { SearchModule } from 'src/engine/core-modules/search/search.module';
import { logicFunctionExecutorModuleFactory } from 'src/engine/core-modules/logic-function-executor/logic-function-executor-module.factory';
import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function-executor/logic-function-executor.module';
import { logicFunctionModuleFactory } from 'src/engine/core-modules/logic-function/logic-function-executor/factories/logic-function-module.factory';
import { LogicFunctionModule } from 'src/engine/core-modules/logic-function/logic-function.module';
import { WorkspaceSSOModule } from 'src/engine/core-modules/sso/sso.module';
import { TelemetryModule } from 'src/engine/core-modules/telemetry/telemetry.module';
import { TwentyConfigModule } from 'src/engine/core-modules/twenty-config/twenty-config.module';
@@ -141,8 +141,8 @@ import { FileModule } from './file/file.module';
CacheStorageModule,
AiModelsModule,
AiBillingModule,
LogicFunctionExecutorModule.forRootAsync({
useFactory: logicFunctionExecutorModuleFactory,
LogicFunctionModule.forRootAsync({
useFactory: logicFunctionModuleFactory,
inject: [TwentyConfigService, FileStorageService],
}),
CodeInterpreterModule.forRootAsync({
@@ -1,30 +0,0 @@
import { Inject, Injectable } from '@nestjs/common';
import {
LogicFunctionExecutorDriver,
type LogicFunctionExecuteParams,
type LogicFunctionExecuteResult,
} from 'src/engine/core-modules/logic-function-executor/drivers/interfaces/logic-function-executor-driver.interface';
import { LOGIC_FUNCTION_EXECUTOR_DRIVER } from 'src/engine/core-modules/logic-function-executor/logic-function-executor.constants';
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
@Injectable()
export class LogicFunctionExecutorService
implements LogicFunctionExecutorDriver
{
constructor(
@Inject(LOGIC_FUNCTION_EXECUTOR_DRIVER)
private driver: LogicFunctionExecutorDriver,
) {}
async delete(flatLogicFunction: FlatLogicFunction): Promise<void> {
return this.driver.delete(flatLogicFunction);
}
async execute(
params: LogicFunctionExecuteParams,
): Promise<LogicFunctionExecuteResult> {
return this.driver.execute(params);
}
}
@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { LogicFunctionBuildService } from 'src/engine/metadata-modules/logic-function-build/logic-function-build.service';
import { LogicFunctionBuildService } from 'src/engine/core-modules/logic-function/logic-function-build/services/logic-function-build.service';
@Module({
providers: [LogicFunctionBuildService],
@@ -7,12 +7,12 @@ import { build } from 'esbuild';
import { FileFolder } from 'twenty-shared/types';
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function-executor/drivers/utils/lambda-build-directory-manager';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import {
getLogicFunctionBaseFolderPath,
getRelativePathFromBase,
} from 'src/engine/metadata-modules/logic-function/utils/get-logic-function-base-folder-path.util';
} from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
export type FunctionBuildParams = {
flatLogicFunction: FlatLogicFunction;
@@ -1,7 +1,7 @@
import {
type LogicFunctionExecutorDriver,
type LogicFunctionExecuteResult,
} from 'src/engine/core-modules/logic-function-executor/drivers/interfaces/logic-function-executor-driver.interface';
} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface';
import {
LogicFunctionException,
@@ -26,16 +26,16 @@ import {
type LogicFunctionExecuteParams,
type LogicFunctionExecuteResult,
type LogicFunctionExecutorDriver,
} from 'src/engine/core-modules/logic-function-executor/drivers/interfaces/logic-function-executor-driver.interface';
} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface';
import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { copyAndBuildDependencies } from 'src/engine/core-modules/logic-function-executor/drivers/utils/copy-and-build-dependencies';
import { copyExecutor } from 'src/engine/core-modules/logic-function-executor/drivers/utils/copy-executor';
import { createZipFile } from 'src/engine/core-modules/logic-function-executor/drivers/utils/create-zip-file';
import { copyAndBuildDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-and-build-dependencies';
import { copyExecutor } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-executor';
import { createZipFile } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/create-zip-file';
import {
LambdaBuildDirectoryManager,
NODE_LAYER_SUBFOLDER,
} from 'src/engine/core-modules/logic-function-executor/drivers/utils/lambda-build-directory-manager';
} from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
import { type FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
import { LogicFunctionRuntime } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
@@ -8,19 +8,19 @@ import {
type LogicFunctionExecutorDriver,
type LogicFunctionExecuteParams,
type LogicFunctionExecuteResult,
} from 'src/engine/core-modules/logic-function-executor/drivers/interfaces/logic-function-executor-driver.interface';
} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface';
import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function-executor/drivers/constants/logic-function-executor-tmpdir-folder';
import { copyAndBuildDependencies } from 'src/engine/core-modules/logic-function-executor/drivers/utils/copy-and-build-dependencies';
import { ConsoleListener } from 'src/engine/core-modules/logic-function-executor/drivers/utils/intercept-console';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function-executor/drivers/utils/lambda-build-directory-manager';
import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-executor-tmpdir-folder';
import { copyAndBuildDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-and-build-dependencies';
import { ConsoleListener } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/intercept-console';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
import { type FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto';
import {
getLogicFunctionBaseFolderPath,
getRelativePathFromBase,
} from 'src/engine/metadata-modules/logic-function/utils/get-logic-function-base-folder-path.util';
} from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
export interface LocalDriverOptions {
fileStorageService: FileStorageService;
@@ -1,18 +1,17 @@
import { type DynamicModule, Global } from '@nestjs/common';
import { type DynamicModule, Module } from '@nestjs/common';
import { AddPackagesCommand } from 'src/engine/core-modules/logic-function-executor/commands/add-packages.command';
import { DisabledDriver } from 'src/engine/core-modules/logic-function-executor/drivers/disabled.driver';
import { LambdaDriver } from 'src/engine/core-modules/logic-function-executor/drivers/lambda.driver';
import { LocalDriver } from 'src/engine/core-modules/logic-function-executor/drivers/local.driver';
import { LOGIC_FUNCTION_EXECUTOR_DRIVER } from 'src/engine/core-modules/logic-function-executor/logic-function-executor.constants';
import {
LogicFunctionExecutorDriverType,
type LogicFunctionExecutorModuleAsyncOptions,
} from 'src/engine/core-modules/logic-function-executor/logic-function-executor.interface';
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function-executor/logic-function-executor.service';
} from 'src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface';
@Global()
export class LogicFunctionExecutorModule {
import { DisabledDriver } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/disabled.driver';
import { LambdaDriver } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver';
import { LocalDriver } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver';
import { LOGIC_FUNCTION_EXECUTOR_DRIVER } from 'src/engine/core-modules/logic-function/logic-function-executor/constants/logic-function-executor.constants';
@Module({})
export class LogicFunctionDriversModule {
static forRootAsync(
options: LogicFunctionExecutorModuleAsyncOptions,
): DynamicModule {
@@ -42,10 +41,10 @@ export class LogicFunctionExecutorModule {
};
return {
module: LogicFunctionExecutorModule,
module: LogicFunctionDriversModule,
imports: options.imports || [],
providers: [LogicFunctionExecutorService, provider, AddPackagesCommand],
exports: [LogicFunctionExecutorService],
providers: [provider],
exports: [LOGIC_FUNCTION_EXECUTOR_DRIVER],
};
}
}
@@ -1,6 +1,6 @@
import { type FlatApplicationVariable } from 'src/engine/core-modules/applicationVariable/types/flat-application-variable.type';
import { type SecretEncryptionService } from 'src/engine/core-modules/secret-encryption/secret-encryption.service';
import { buildEnvVar } from 'src/engine/core-modules/logic-function-executor/drivers/utils/build-env-var';
import { buildEnvVar } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/build-env-var';
describe('buildEnvVar', () => {
const mockSecretEncryptionService = {
@@ -3,7 +3,7 @@ import { promises as fs, statSync } from 'fs';
import { join } from 'path';
import { promisify } from 'util';
import { getLayerDependenciesDirName } from 'src/engine/core-modules/logic-function-executor/drivers/utils/get-layer-dependencies-dir-name';
import { getLayerDependenciesDirName } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/get-layer-dependencies-dir-name';
import { type FlatLogicFunctionLayer } from 'src/engine/metadata-modules/logic-function-layer/types/flat-logic-function-layer.type';
const execFilePromise = promisify(execFile);
@@ -1,6 +1,6 @@
import { promises as fs } from 'fs';
import { getExecutorFilePath } from 'src/engine/core-modules/logic-function-executor/drivers/utils/get-executor-file-path';
import { getExecutorFilePath } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/get-executor-file-path';
export const copyExecutor = async (buildDirectory: string) => {
await fs.mkdir(buildDirectory, {
@@ -5,7 +5,7 @@ import { ASSET_PATH } from 'src/constants/assets-path';
export const getExecutorFilePath = (): string => {
const baseTypescriptProjectPath = path.join(
ASSET_PATH,
`engine/core-modules/logic-function-executor/drivers/constants/executor`,
`engine/core-modules/logic-function/logic-function-drivers/constants/executor`,
);
return path.resolve(__dirname, baseTypescriptProjectPath);
@@ -3,8 +3,8 @@ import { join } from 'path';
import { type PackageJson } from 'twenty-shared/application';
import { getLayerDependenciesDirName } from 'src/engine/core-modules/logic-function-executor/drivers/utils/get-layer-dependencies-dir-name';
import { LAST_LAYER_VERSION } from 'src/engine/core-modules/logic-function-executor/drivers/layers/last-layer-version';
import { getLayerDependenciesDirName } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/get-layer-dependencies-dir-name';
import { LAST_LAYER_VERSION } from 'src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version';
export type LayerDependencies = {
packageJson: PackageJson;
@@ -7,7 +7,7 @@ export const getLayerDependenciesDirName = (
): string => {
const baseTypescriptProjectPath = path.join(
ASSET_PATH,
`engine/core-modules/logic-function-executor/drivers/layers/${version}`,
`engine/core-modules/logic-function/logic-function-drivers/layers/${version}`,
);
return path.resolve(__dirname, baseTypescriptProjectPath);
@@ -32,7 +32,7 @@ const getAllFiles = async (
export const getSeedProjectFiles = (async () => {
const seedProjectPath = join(
ASSET_PATH,
`engine/core-modules/logic-function-executor/drivers/constants/seed-project`,
`engine/core-modules/logic-function/logic-function-drivers/constants/seed-project`,
);
return await getAllFiles(seedProjectPath);
@@ -3,7 +3,7 @@ import * as fs from 'fs/promises';
import { v4 } from 'uuid';
import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function-executor/drivers/constants/logic-function-executor-tmpdir-folder';
import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-executor-tmpdir-folder';
export const NODE_LAYER_SUBFOLDER = 'nodejs';
@@ -36,7 +36,7 @@ export class AddPackagesCommand extends CommandRunner {
this.logger.log('');
const layersFolder = this.getAbsoluteFilePath(
`src/engine/core-modules/logic-function-executor/drivers/layers`,
`src/engine/core-modules/logic-function/logic-function-drivers/layers`,
);
const currentVersion = await this.getLastLayerVersion();
@@ -108,7 +108,7 @@ export class AddPackagesCommand extends CommandRunner {
private async getLastLayerVersion() {
const filePath = this.getAbsoluteFilePath(
'src/engine/core-modules/logic-function-executor/drivers/layers/last-layer-version.ts',
'src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version.ts',
);
const content = await fs.readFile(filePath, 'utf8');
@@ -123,7 +123,7 @@ export class AddPackagesCommand extends CommandRunner {
private async updateLastLayerVersion(newVersion: number) {
const filePath = this.getAbsoluteFilePath(
'src/engine/core-modules/logic-function-executor/drivers/layers/last-layer-version.ts',
'src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version.ts',
);
await fs.writeFile(
@@ -1,13 +1,14 @@
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import {
LogicFunctionExecutorDriverType,
type LogicFunctionExecutorModuleOptions,
} from 'src/engine/core-modules/logic-function-executor/logic-function-executor.interface';
} from 'src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface';
import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { type TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
export const logicFunctionExecutorModuleFactory = async (
export const logicFunctionModuleFactory = async (
twentyConfigService: TwentyConfigService,
fileStorageService: FileStorageService,
): Promise<LogicFunctionExecutorModuleOptions> => {
@@ -1,7 +1,7 @@
import { type FactoryProvider, type ModuleMetadata } from '@nestjs/common';
import { type LambdaDriverOptions } from 'src/engine/core-modules/logic-function-executor/drivers/lambda.driver';
import { type LocalDriverOptions } from 'src/engine/core-modules/logic-function-executor/drivers/local.driver';
import { type LambdaDriverOptions } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver';
import { type LocalDriverOptions } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver';
export enum LogicFunctionExecutorDriverType {
DISABLED = 'DISABLED',
@@ -0,0 +1,26 @@
import { Module } from '@nestjs/common';
import { AuditModule } from 'src/engine/core-modules/audit/audit.module';
import { TokenModule } from 'src/engine/core-modules/auth/token/token.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 { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
@Module({
imports: [
ThrottlerModule,
AuditModule,
TokenModule,
SecretEncryptionModule,
SubscriptionsModule,
WorkspaceCacheModule,
LogicFunctionBuildModule,
],
providers: [LogicFunctionExecutorService, AddPackagesCommand],
exports: [LogicFunctionExecutorService],
})
export class LogicFunctionExecutorModule {}
@@ -0,0 +1,261 @@
import { Inject, Injectable } from '@nestjs/common';
import {
DEFAULT_API_KEY_NAME,
DEFAULT_API_URL_NAME,
} from 'twenty-shared/application';
import { isDefined } from 'twenty-shared/utils';
import {
LogicFunctionExecutorDriver,
type LogicFunctionExecuteParams,
type LogicFunctionExecuteResult,
} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface';
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 { LogicFunctionBuildService } from 'src/engine/core-modules/logic-function/logic-function-build/services/logic-function-build.service';
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 { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
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';
import { cleanServerUrl } from 'src/utils/clean-server-url';
const MIN_TOKEN_EXPIRATION_IN_SECONDS = 5;
export class LogicFunctionExecutionException extends Error {
constructor(
message: string,
public readonly code: LogicFunctionExecutionExceptionCode,
) {
super(message);
this.name = 'LogicFunctionExecutionException';
}
}
export enum LogicFunctionExecutionExceptionCode {
LOGIC_FUNCTION_NOT_FOUND = 'LOGIC_FUNCTION_NOT_FOUND',
RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
}
@Injectable()
export class LogicFunctionExecutorService
implements LogicFunctionExecutorDriver
{
constructor(
@Inject(LOGIC_FUNCTION_EXECUTOR_DRIVER)
private driver: LogicFunctionExecutorDriver,
private readonly throttlerService: ThrottlerService,
private readonly twentyConfigService: TwentyConfigService,
private readonly workspaceCacheService: WorkspaceCacheService,
private readonly applicationTokenService: ApplicationTokenService,
private readonly secretEncryptionService: SecretEncryptionService,
private readonly functionBuildService: LogicFunctionBuildService,
private readonly subscriptionService: SubscriptionService,
private readonly auditService: AuditService,
) {}
async delete(flatLogicFunction: FlatLogicFunction): Promise<void> {
return this.driver.delete(flatLogicFunction);
}
async execute(
params: LogicFunctionExecuteParams,
): Promise<LogicFunctionExecuteResult> {
return this.driver.execute(params);
}
async executeOneLogicFunction({
id,
workspaceId,
payload,
}: {
id: string;
workspaceId: string;
payload: object;
}): Promise<LogicFunctionExecuteResult> {
await this.throttleExecution(workspaceId);
const {
flatLogicFunctionMaps,
flatApplicationMaps,
applicationVariableMaps,
logicFunctionLayerMaps,
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatLogicFunctionMaps',
'flatApplicationMaps',
'applicationVariableMaps',
'logicFunctionLayerMaps',
]);
const flatLogicFunction = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: id,
flatEntityMaps: flatLogicFunctionMaps,
});
if (
!isDefined(flatLogicFunction) ||
isDefined(flatLogicFunction.deletedAt)
) {
throw new LogicFunctionExecutionException(
`Logic function with id ${id} not found`,
LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND,
);
}
const flatLogicFunctionLayer =
logicFunctionLayerMaps.byId[flatLogicFunction.logicFunctionLayerId];
if (!isDefined(flatLogicFunctionLayer)) {
throw new LogicFunctionExecutionException(
`Logic function layer with id ${flatLogicFunction.logicFunctionLayerId} not found`,
LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND,
);
}
const applicationAccessToken = isDefined(flatLogicFunction.applicationId)
? await this.applicationTokenService.generateApplicationToken({
workspaceId,
applicationId: flatLogicFunction.applicationId,
expiresInSeconds: Math.max(
flatLogicFunction.timeoutSeconds,
MIN_TOKEN_EXPIRATION_IN_SECONDS,
),
})
: undefined;
const baseUrl = cleanServerUrl(this.twentyConfigService.get('SERVER_URL'));
const flatApplicationVariables = isDefined(flatLogicFunction.applicationId)
? (applicationVariableMaps.byApplicationId[
flatLogicFunction.applicationId
] ?? [])
: [];
const envVariables = {
...(isDefined(baseUrl)
? {
[DEFAULT_API_URL_NAME]: baseUrl,
}
: {}),
...(isDefined(applicationAccessToken)
? {
[DEFAULT_API_KEY_NAME]: applicationAccessToken.token,
}
: {}),
...buildEnvVar(flatApplicationVariables, this.secretEncryptionService),
};
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 ${flatLogicFunction.id}`,
LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND,
);
}
if (
!(await this.functionBuildService.isBuilt({
flatLogicFunction,
applicationUniversalIdentifier,
}))
) {
await this.functionBuildService.buildAndUpload({
flatLogicFunction,
applicationUniversalIdentifier,
});
}
const resultLogicFunction = await this.callWithTimeout({
callback: () =>
this.execute({
flatLogicFunction,
flatLogicFunctionLayer,
applicationUniversalIdentifier,
payload,
env: envVariables,
}),
timeoutMs: flatLogicFunction.timeoutSeconds * 1000,
});
if (this.twentyConfigService.get('LOGIC_FUNCTION_LOGS_ENABLED')) {
/* eslint-disable no-console */
console.log(resultLogicFunction.logs);
}
await this.subscriptionService.publish({
channel: SubscriptionChannel.LOGIC_FUNCTION_LOGS_CHANNEL,
workspaceId,
payload: {
logicFunctionLogs: {
logs: resultLogicFunction.logs,
id: flatLogicFunction.id,
name: flatLogicFunction.name,
universalIdentifier: flatLogicFunction.universalIdentifier,
applicationId: flatLogicFunction.applicationId,
applicationUniversalIdentifier,
},
},
});
this.auditService
.createContext({
workspaceId,
})
.insertWorkspaceEvent(LOGIC_FUNCTION_EXECUTED_EVENT, {
duration: resultLogicFunction.duration,
status: resultLogicFunction.status,
...(resultLogicFunction.error && {
errorType: resultLogicFunction.error.errorType,
}),
functionId: flatLogicFunction.id,
functionName: flatLogicFunction.name,
});
return resultLogicFunction;
}
private async throttleExecution(workspaceId: string) {
try {
await this.throttlerService.tokenBucketThrottleOrThrow(
`${workspaceId}-logic-function-execution`,
1,
this.twentyConfigService.get('LOGIC_FUNCTION_EXEC_THROTTLE_LIMIT'),
this.twentyConfigService.get('LOGIC_FUNCTION_EXEC_THROTTLE_TTL'),
);
} catch {
throw new LogicFunctionExecutionException(
'Logic function execution rate limit exceeded',
LogicFunctionExecutionExceptionCode.RATE_LIMIT_EXCEEDED,
);
}
}
private async callWithTimeout<T>({
callback,
timeoutMs,
}: {
callback: () => Promise<T>;
timeoutMs: number;
}): Promise<T> {
return Promise.race([
callback(),
new Promise<T>((_, reject) =>
setTimeout(() => reject(new Error('Execution timed out')), timeoutMs),
),
]);
}
}
@@ -0,0 +1,16 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
import { LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
@Module({
imports: [
TypeOrmModule.forFeature([LogicFunctionLayerEntity]),
WorkspaceCacheModule,
],
providers: [LogicFunctionLayerService],
exports: [LogicFunctionLayerService],
})
export class CoreLogicFunctionLayerModule {}
@@ -8,7 +8,7 @@ import type { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialE
import { LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
import { CreateLogicFunctionLayerInput } from 'src/engine/metadata-modules/logic-function-layer/dtos/create-logic-function-layer.input';
import { getLastCommonLayerDependencies } from 'src/engine/core-modules/logic-function-executor/drivers/utils/get-last-common-layer-dependencies';
import { getLastCommonLayerDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/get-last-common-layer-dependencies';
import { logicFunctionCreateHash } from 'src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
@@ -3,7 +3,7 @@ import { Scope } from '@nestjs/common';
import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator';
import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
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';
export type LogicFunctionTriggerJobData = {
logicFunctionId: string;
@@ -16,17 +16,19 @@ export type LogicFunctionTriggerJobData = {
scope: Scope.REQUEST,
})
export class LogicFunctionTriggerJob {
constructor(private readonly logicFunctionService: LogicFunctionService) {}
constructor(
private readonly logicFunctionExecutorService: LogicFunctionExecutorService,
) {}
@Process(LogicFunctionTriggerJob.name)
async handle(logicFunctionPayloads: LogicFunctionTriggerJobData[]) {
await Promise.all(
logicFunctionPayloads.map(
async (logicFunctionPayload) =>
await this.logicFunctionService.executeOneLogicFunction({
await this.logicFunctionExecutorService.executeOneLogicFunction({
id: logicFunctionPayload.logicFunctionId,
workspaceId: logicFunctionPayload.workspaceId,
payload: logicFunctionPayload.payload || {},
payload: logicFunctionPayload.payload ?? {},
}),
),
);
@@ -0,0 +1,29 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TokenModule } from 'src/engine/core-modules/auth/token/token.module';
import { WorkspaceDomainsModule } from 'src/engine/core-modules/domain/workspace-domains/workspace-domains.module';
import { LogicFunctionTriggerJob } from 'src/engine/core-modules/logic-function/logic-function-trigger/jobs/logic-function-trigger.job';
import { CronTriggerCronCommand } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/cron/cron-trigger.cron.command';
import { CronTriggerCronJob } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/cron/cron-trigger.cron.job';
import { CallDatabaseEventTriggerJobsJob } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/database-event/call-database-event-trigger-jobs.job';
import { RouteTriggerService } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
@Module({
imports: [
TypeOrmModule.forFeature([LogicFunctionEntity, WorkspaceEntity]),
TokenModule,
WorkspaceDomainsModule,
],
providers: [
LogicFunctionTriggerJob,
CronTriggerCronJob,
CronTriggerCronCommand,
CallDatabaseEventTriggerJobsJob,
RouteTriggerService,
],
exports: [CronTriggerCronCommand, RouteTriggerService],
})
export class LogicFunctionTriggerModule {}
@@ -6,7 +6,8 @@ import { MessageQueueService } from 'src/engine/core-modules/message-queue/servi
import {
CRON_TRIGGER_CRON_PATTERN,
CronTriggerCronJob,
} from 'src/engine/metadata-modules/cron-trigger/crons/jobs/cron-trigger.cron.job';
} from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/cron/cron-trigger.cron.job';
@Command({
name: 'cron:trigger:start-cron-trigger',
description: 'Starts a cron job to trigger cron triggered logic functions',
@@ -14,7 +14,7 @@ import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.ent
import {
LogicFunctionTriggerJob,
LogicFunctionTriggerJobData,
} from 'src/engine/metadata-modules/logic-function/jobs/logic-function-trigger.job';
} from 'src/engine/core-modules/logic-function/logic-function-trigger/jobs/logic-function-trigger.job';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { shouldRunNow } from 'src/utils/should-run-now.utils';
@@ -11,11 +11,11 @@ import { Process } from 'src/engine/core-modules/message-queue/decorators/proces
import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator';
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
import { transformEventBatchToEventPayloads } from 'src/engine/metadata-modules/database-event-trigger/utils/transform-event-batch-to-event-payloads';
import { transformEventBatchToEventPayloads } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/database-event/utils/transform-event-batch-to-event-payloads';
import {
LogicFunctionTriggerJob,
LogicFunctionTriggerJobData,
} from 'src/engine/metadata-modules/logic-function/jobs/logic-function-trigger.job';
} from 'src/engine/core-modules/logic-function/logic-function-trigger/jobs/logic-function-trigger.job';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event-batch.type';
@@ -1,6 +1,6 @@
import type { ObjectRecordEvent } from 'twenty-shared/database-events';
import { transformEventBatchToEventPayloads } from 'src/engine/metadata-modules/database-event-trigger/utils/transform-event-batch-to-event-payloads';
import { transformEventBatchToEventPayloads } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/database-event/utils/transform-event-batch-to-event-payloads';
import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock';
import { type LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import type { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event-batch.type';
@@ -5,7 +5,7 @@ import type {
ObjectRecordEvent,
} from 'twenty-shared/database-events';
import { type LogicFunctionTriggerJobData } from 'src/engine/metadata-modules/logic-function/jobs/logic-function-trigger.job';
import { type LogicFunctionTriggerJobData } from 'src/engine/core-modules/logic-function/logic-function-trigger/jobs/logic-function-trigger.job';
import { type LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import type { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event-batch.type';
@@ -9,7 +9,7 @@ import type { Response } from 'express';
import {
RouteTriggerException,
RouteTriggerExceptionCode,
} from 'src/engine/metadata-modules/route-trigger/exceptions/route-trigger.exception';
} from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/exceptions/route-trigger.exception';
import type { CustomException } from 'src/utils/custom-exception';
import { HttpExceptionHandlerService } from 'src/engine/core-modules/exception-handler/http-exception-handler.service';
@@ -9,19 +9,19 @@ import { HTTPMethod } from 'twenty-shared/types';
import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service';
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service';
import {
RouteTriggerException,
RouteTriggerExceptionCode,
} from 'src/engine/metadata-modules/route-trigger/exceptions/route-trigger.exception';
import { buildLogicFunctionEvent } from 'src/engine/metadata-modules/route-trigger/utils/build-logic-function-event.util';
} from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/exceptions/route-trigger.exception';
import { buildLogicFunctionEvent } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/utils/build-logic-function-event.util';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service';
@Injectable()
export class RouteTriggerService {
constructor(
private readonly accessTokenService: AccessTokenService,
private readonly logicFunctionService: LogicFunctionService,
private readonly logicFunctionExecutorService: LogicFunctionExecutorService,
private readonly workspaceDomainsService: WorkspaceDomainsService,
@InjectRepository(LogicFunctionEntity)
private readonly logicFunctionRepository: Repository<LogicFunctionEntity>,
@@ -146,11 +146,12 @@ export class RouteTriggerService {
forwardedRequestHeaders: httpRouteSettings?.forwardedRequestHeaders ?? [],
});
const result = await this.logicFunctionService.executeOneLogicFunction({
id: logicFunction.id,
workspaceId: logicFunction.workspaceId,
payload: event,
});
const result =
await this.logicFunctionExecutorService.executeOneLogicFunction({
id: logicFunction.id,
workspaceId: logicFunction.workspaceId,
payload: event,
});
if (!isDefined(result)) {
return result;
@@ -6,7 +6,7 @@ import {
filterRequestHeaders,
normalizePathParameters,
normalizeQueryStringParameters,
} from 'src/engine/metadata-modules/route-trigger/utils/build-logic-function-event.util';
} from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/utils/build-logic-function-event.util';
describe('filterRequestHeaders', () => {
it('should filter headers based on allowed names', () => {
@@ -22,7 +22,6 @@ export const filterRequestHeaders = ({
const headerValue = requestHeaders[headerName];
if (headerValue !== undefined) {
// Convert string[] to comma-separated string (as per HTTP spec)
filteredHeaders[headerName] = Array.isArray(headerValue)
? headerValue.join(', ')
: headerValue;
@@ -42,22 +41,18 @@ export const extractBody = (request: Request): object | null => {
return null;
}
// If body is already an object (parsed JSON by body-parser), return as-is
if (typeof request.body === 'object' && !Buffer.isBuffer(request.body)) {
return request.body;
}
// If body is a string, try to parse as JSON
if (typeof request.body === 'string') {
try {
return JSON.parse(request.body);
} catch {
// If not valid JSON, wrap in an object
return { raw: request.body };
}
}
// If body is a Buffer, try to parse as JSON
if (Buffer.isBuffer(request.body)) {
try {
return JSON.parse(request.body.toString('utf-8'));
@@ -84,7 +79,6 @@ export const normalizeQueryStringParameters = (
}
if (Array.isArray(value)) {
// Join array values with commas
const stringValues = value.filter(
(v): v is string => typeof v === 'string',
);
@@ -93,8 +87,6 @@ export const normalizeQueryStringParameters = (
} else if (typeof value === 'string') {
normalized[key] = value;
} else if (typeof value === 'object') {
// Handle nested query objects (e.g., ?foo[bar]=baz)
// This is uncommon in REST APIs, convert to JSON string as fallback
normalized[key] = JSON.stringify(value);
}
}
@@ -0,0 +1,35 @@
import { type DynamicModule, Global, Module } from '@nestjs/common';
import { type LogicFunctionExecutorModuleAsyncOptions } from 'src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface';
import { LogicFunctionBuildModule } from 'src/engine/core-modules/logic-function/logic-function-build/logic-function-build.module';
import { LogicFunctionDriversModule } from 'src/engine/core-modules/logic-function/logic-function-drivers/logic-function-drivers.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 { LogicFunctionTriggerModule } from 'src/engine/core-modules/logic-function/logic-function-trigger/logic-function-trigger.module';
@Global()
@Module({})
export class LogicFunctionModule {
static forRootAsync(
options: LogicFunctionExecutorModuleAsyncOptions,
): DynamicModule {
return {
module: LogicFunctionModule,
imports: [
LogicFunctionDriversModule.forRootAsync(options),
LogicFunctionExecutorModule,
LogicFunctionBuildModule,
CoreLogicFunctionLayerModule,
LogicFunctionTriggerModule,
],
exports: [
LogicFunctionDriversModule,
LogicFunctionExecutorModule,
LogicFunctionBuildModule,
CoreLogicFunctionLayerModule,
LogicFunctionTriggerModule,
],
};
}
}
@@ -20,9 +20,7 @@ import { HandleWorkspaceMemberDeletedJob } from 'src/engine/core-modules/workspa
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.module';
import { AiAgentMonitorModule } from 'src/engine/metadata-modules/ai/ai-agent-monitor/ai-agent-monitor.module';
import { CronTriggerModule } from 'src/engine/metadata-modules/cron-trigger/cron-trigger.module';
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
import { DatabaseEventTriggerModule } from 'src/engine/metadata-modules/database-event-trigger/database-event-trigger.module';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module';
@@ -68,8 +66,6 @@ import { WorkflowModule } from 'src/modules/workflow/workflow.module';
SubscriptionsModule,
AuditJobModule,
AiAgentMonitorModule,
CronTriggerModule,
DatabaseEventTriggerModule,
LogicFunctionModule,
],
providers: [
@@ -15,6 +15,7 @@ import { type LoggerOptions } from 'typeorm/logger/LoggerOptions';
import { type AwsRegion } from 'src/engine/core-modules/twenty-config/interfaces/aws-region.interface';
import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interfaces/node-environment.interface';
import { SupportDriver } from 'src/engine/core-modules/twenty-config/interfaces/support.interface';
import { LogicFunctionExecutorDriverType } from 'src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface';
import { CaptchaDriverType } from 'src/engine/core-modules/captcha/interfaces';
import { CodeInterpreterDriverType } from 'src/engine/core-modules/code-interpreter/code-interpreter.interface';
@@ -22,7 +23,6 @@ import { EmailDriver } from 'src/engine/core-modules/email/enums/email-driver.en
import { ExceptionHandlerDriver } from 'src/engine/core-modules/exception-handler/interfaces';
import { StorageDriverType } from 'src/engine/core-modules/file-storage/interfaces';
import { LoggerDriverType } from 'src/engine/core-modules/logger/interfaces';
import { LogicFunctionExecutorDriverType } from 'src/engine/core-modules/logic-function-executor/logic-function-executor.interface';
import { type MeterDriver } from 'src/engine/core-modules/metrics/types/meter-driver.type';
import { CastToLogLevelArray } from 'src/engine/core-modules/twenty-config/decorators/cast-to-log-level-array.decorator';
import { CastToMeterDriverArray } from 'src/engine/core-modules/twenty-config/decorators/cast-to-meter-driver.decorator';
@@ -1,14 +0,0 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { CronTriggerCronCommand } from 'src/engine/metadata-modules/cron-trigger/crons/commands/cron-trigger.cron.command';
import { CronTriggerCronJob } from 'src/engine/metadata-modules/cron-trigger/crons/jobs/cron-trigger.cron.job';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
@Module({
imports: [TypeOrmModule.forFeature([WorkspaceEntity, LogicFunctionEntity])],
providers: [CronTriggerCronJob, CronTriggerCronCommand],
exports: [CronTriggerCronCommand],
})
export class CronTriggerModule {}
@@ -1,12 +0,0 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { CallDatabaseEventTriggerJobsJob } from 'src/engine/metadata-modules/database-event-trigger/jobs/call-database-event-trigger-jobs.job';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
@Module({
imports: [TypeOrmModule.forFeature([LogicFunctionEntity])],
providers: [CallDatabaseEventTriggerJobsJob],
exports: [],
})
export class DatabaseEventTriggerModule {}
@@ -4,24 +4,17 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
import { LogicFunctionLayerEntity } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.entity';
import { LogicFunctionLayerResolver } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.resolver';
import { LogicFunctionLayerService } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.service';
import { WorkspaceLogicFunctionLayerMapCacheService } from 'src/engine/metadata-modules/logic-function-layer/services/workspace-logic-function-layer-map-cache.service';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
@Module({
imports: [
PermissionsModule,
TypeOrmModule.forFeature([LogicFunctionLayerEntity]),
WorkspaceCacheModule,
PermissionsModule,
],
providers: [
LogicFunctionLayerService,
LogicFunctionLayerResolver,
WorkspaceLogicFunctionLayerMapCacheService,
],
exports: [
LogicFunctionLayerService,
WorkspaceLogicFunctionLayerMapCacheService,
],
exports: [WorkspaceLogicFunctionLayerMapCacheService],
})
export class LogicFunctionLayerModule {}
@@ -9,7 +9,7 @@ import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.g
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
import { CreateLogicFunctionLayerInput } from 'src/engine/metadata-modules/logic-function-layer/dtos/create-logic-function-layer.input';
import { LogicFunctionLayerDTO } from 'src/engine/metadata-modules/logic-function-layer/dtos/logic-function-layer.dto';
import { LogicFunctionLayerService } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.service';
import { LogicFunctionLayerService } from 'src/engine/core-modules/logic-function/logic-function-layer/services/logic-function-layer.service';
@UseGuards(WorkspaceAuthGuard)
@Resolver()
@@ -1 +0,0 @@
export const LOGIC_FUNCTION_PUBLISHED = 'logic_function_published';
@@ -1,9 +0,0 @@
import { ID, InputType } from '@nestjs/graphql';
import { IDField } from '@ptc-org/nestjs-query-graphql';
@InputType()
export class BuildDraftLogicFunctionInput {
@IDField(() => ID, { description: 'The id of the function.' })
id!: string;
}
@@ -14,9 +14,7 @@ import { FileModule } from 'src/engine/core-modules/file/file.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 { LogicFunctionBuildModule } from 'src/engine/metadata-modules/logic-function-build/logic-function-build.module';
import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module';
import { LogicFunctionTriggerJob } from 'src/engine/metadata-modules/logic-function/jobs/logic-function-trigger.job';
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';
@@ -40,7 +38,6 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
PermissionsModule,
WorkspaceManyOrAllFlatEntityMapsCacheModule,
WorkspaceMigrationModule,
LogicFunctionBuildModule,
LogicFunctionLayerModule,
SubscriptionsModule,
WorkspaceCacheModule,
@@ -50,7 +47,6 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
providers: [
LogicFunctionService,
LogicFunctionV2Service,
LogicFunctionTriggerJob,
LogicFunctionResolver,
WorkspaceFlatLogicFunctionMapCacheService,
],
@@ -1,31 +1,25 @@
import { 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 { FileStorageExceptionCode } from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception';
import { type LogicFunctionExecuteResult } from 'src/engine/core-modules/logic-function-executor/drivers/interfaces/logic-function-executor-driver.interface';
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 { 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 { SecretEncryptionService } from 'src/engine/core-modules/secret-encryption/secret-encryption.service';
import { buildEnvVar } from 'src/engine/core-modules/logic-function-executor/drivers/utils/build-env-var';
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function-executor/logic-function-executor.service';
import { ThrottlerService } from 'src/engine/core-modules/throttler/throttler.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { getLogicFunctionBaseFolderPath } from 'src/engine/metadata-modules/logic-function/utils/get-logic-function-base-folder-path.util';
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 { LogicFunctionLayerService } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.service';
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';
@@ -37,35 +31,23 @@ import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-functi
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 { 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';
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';
import { cleanServerUrl } from 'src/utils/clean-server-url';
import { LogicFunctionBuildService } from 'src/engine/metadata-modules/logic-function-build/logic-function-build.service';
const MIN_TOKEN_EXPIRATION_IN_SECONDS = 5;
@Injectable()
export class LogicFunctionService {
constructor(
private readonly fileStorageService: FileStorageService,
private readonly logicFunctionExecutorService: LogicFunctionExecutorService,
private readonly functionBuildService: LogicFunctionBuildService,
private readonly logicFunctionLayerService: LogicFunctionLayerService,
private readonly logicFunctionExecutorService: LogicFunctionExecutorService,
@InjectRepository(LogicFunctionEntity)
private readonly logicFunctionRepository: Repository<LogicFunctionEntity>,
private readonly throttlerService: ThrottlerService,
private readonly twentyConfigService: TwentyConfigService,
private readonly auditService: AuditService,
private readonly applicationTokenService: ApplicationTokenService,
private readonly subscriptionService: SubscriptionService,
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
private readonly applicationService: ApplicationService,
private readonly workspaceCacheService: WorkspaceCacheService,
private readonly secretEncryptionService: SecretEncryptionService,
) {}
async getLogicFunctionSourceCode(workspaceId: string, id: string) {
@@ -122,142 +104,29 @@ export class LogicFunctionService {
workspaceId: string;
payload: object;
}): Promise<LogicFunctionExecuteResult> {
await this.throttleExecution(workspaceId);
const {
flatLogicFunctionMaps,
flatApplicationMaps,
applicationVariableMaps,
logicFunctionLayerMaps,
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
'flatLogicFunctionMaps',
'flatApplicationMaps',
'applicationVariableMaps',
'logicFunctionLayerMaps',
]);
const flatLogicFunction = findFlatLogicFunctionOrThrow({
id,
flatLogicFunctionMaps,
});
const flatLogicFunctionLayer =
logicFunctionLayerMaps.byId[flatLogicFunction.logicFunctionLayerId];
if (!isDefined(flatLogicFunctionLayer)) {
throw new LogicFunctionException(
`Logic function layer with id ${flatLogicFunction.logicFunctionLayerId} not found`,
LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND,
);
}
const applicationAccessToken = isDefined(flatLogicFunction.applicationId)
? await this.applicationTokenService.generateApplicationToken({
workspaceId,
applicationId: flatLogicFunction.applicationId,
expiresInSeconds: Math.max(
flatLogicFunction.timeoutSeconds,
MIN_TOKEN_EXPIRATION_IN_SECONDS,
),
})
: undefined;
const baseUrl = cleanServerUrl(this.twentyConfigService.get('SERVER_URL'));
const flatApplicationVariables = isDefined(flatLogicFunction.applicationId)
? (applicationVariableMaps.byApplicationId[
flatLogicFunction.applicationId
] ?? [])
: [];
const envVariables = {
...(isDefined(baseUrl)
? {
[DEFAULT_API_URL_NAME]: baseUrl,
}
: {}),
...(isDefined(applicationAccessToken)
? {
[DEFAULT_API_KEY_NAME]: applicationAccessToken.token,
}
: {}),
...buildEnvVar(flatApplicationVariables, this.secretEncryptionService),
};
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 ${flatLogicFunction.id}`,
LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_FOUND,
);
}
// We keep that check to build functions
if (
!(await this.functionBuildService.isBuilt({
flatLogicFunction,
applicationUniversalIdentifier,
}))
) {
await this.functionBuildService.buildAndUpload({
flatLogicFunction,
applicationUniversalIdentifier,
});
}
const resultLogicFunction = await this.callWithTimeout({
callback: () =>
this.logicFunctionExecutorService.execute({
flatLogicFunction,
flatLogicFunctionLayer,
applicationUniversalIdentifier,
payload,
env: envVariables,
}),
timeoutMs: flatLogicFunction.timeoutSeconds * 1000,
});
if (this.twentyConfigService.get('LOGIC_FUNCTION_LOGS_ENABLED')) {
/* eslint-disable no-console */
console.log(resultLogicFunction.logs);
}
await this.subscriptionService.publish({
channel: SubscriptionChannel.LOGIC_FUNCTION_LOGS_CHANNEL,
workspaceId,
payload: {
logicFunctionLogs: {
logs: resultLogicFunction.logs,
id: flatLogicFunction.id,
name: flatLogicFunction.name,
universalIdentifier: flatLogicFunction.universalIdentifier,
applicationId: flatLogicFunction.applicationId,
applicationUniversalIdentifier,
},
},
});
this.auditService
.createContext({
try {
return await this.logicFunctionExecutorService.executeOneLogicFunction({
id,
workspaceId,
})
.insertWorkspaceEvent(LOGIC_FUNCTION_EXECUTED_EVENT, {
duration: resultLogicFunction.duration,
status: resultLogicFunction.status,
...(resultLogicFunction.error && {
errorType: resultLogicFunction.error.errorType,
}),
functionId: flatLogicFunction.id,
functionName: flatLogicFunction.name,
payload,
});
return resultLogicFunction;
} 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({
@@ -672,47 +541,4 @@ export class LogicFunctionService {
return newFlatLogicFunction;
}
private async throttleExecution(workspaceId: string) {
try {
await this.throttlerService.tokenBucketThrottleOrThrow(
`${workspaceId}-logic-function-execution`,
1,
this.twentyConfigService.get('LOGIC_FUNCTION_EXEC_THROTTLE_LIMIT'),
this.twentyConfigService.get('LOGIC_FUNCTION_EXEC_THROTTLE_TTL'),
);
} catch {
throw new LogicFunctionException(
'Logic function execution rate limit exceeded',
LogicFunctionExceptionCode.LOGIC_FUNCTION_EXECUTION_LIMIT_REACHED,
);
}
}
private async callWithTimeout<T>({
callback,
timeoutMs,
}: {
callback: () => Promise<T>;
timeoutMs: number;
}): Promise<T> {
let timeoutId: NodeJS.Timeout;
const timeoutPromise = new Promise<never>((_, reject) => {
timeoutId = setTimeout(
() =>
reject(
new LogicFunctionException(
`Execution timeout: ${timeoutMs / 1000}s`,
LogicFunctionExceptionCode.LOGIC_FUNCTION_EXECUTION_TIMEOUT,
),
),
timeoutMs,
);
});
return Promise.race([callback(), timeoutPromise]).finally(() =>
clearTimeout(timeoutId),
) as Promise<T>;
}
}
@@ -15,8 +15,8 @@ import { HTTPMethod } from 'twenty-shared/types';
import { NoPermissionGuard } from 'src/engine/guards/no-permission.guard';
import { PublicEndpointGuard } from 'src/engine/guards/public-endpoint.guard';
import { RouteTriggerRestApiExceptionFilter } from 'src/engine/metadata-modules/route-trigger/exceptions/route-trigger-rest-api-exception-filter';
import { RouteTriggerService } from 'src/engine/metadata-modules/route-trigger/route-trigger.service';
import { RouteTriggerRestApiExceptionFilter } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/exceptions/route-trigger-rest-api-exception-filter';
import { RouteTriggerService } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service';
@Controller('s')
@UseGuards(PublicEndpointGuard, NoPermissionGuard)
@@ -1,22 +1,8 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TokenModule } from 'src/engine/core-modules/auth/token/token.module';
import { WorkspaceDomainsModule } from 'src/engine/core-modules/domain/workspace-domains/workspace-domains.module';
import { RouteTriggerController } from 'src/engine/metadata-modules/route-trigger/route-trigger.controller';
import { RouteTriggerService } from 'src/engine/metadata-modules/route-trigger/route-trigger.service';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
@Module({
imports: [
TypeOrmModule.forFeature([LogicFunctionEntity]),
TokenModule,
WorkspaceDomainsModule,
LogicFunctionModule,
],
controllers: [RouteTriggerController],
providers: [RouteTriggerService],
exports: [],
})
export class RouteTriggerModule {}
@@ -13,9 +13,9 @@ import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-mana
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { getSeedProjectFiles } from 'src/engine/core-modules/logic-function-executor/drivers/utils/get-seed-project-files';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function-executor/drivers/utils/lambda-build-directory-manager';
import { getLogicFunctionBaseFolderPath } from 'src/engine/metadata-modules/logic-function/utils/get-logic-function-base-folder-path.util';
import { getSeedProjectFiles } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/get-seed-project-files';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import {
LogicFunctionException,
@@ -24,7 +24,7 @@ import {
import { CreateLogicFunctionAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/logic-function/types/workspace-migration-logic-function-action.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import { LogicFunctionBuildService } from 'src/engine/metadata-modules/logic-function-build/logic-function-build.service';
import { LogicFunctionBuildService } from 'src/engine/core-modules/logic-function/logic-function-build/services/logic-function-build.service';
@Injectable()
export class CreateLogicFunctionActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -7,7 +7,7 @@ import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-mana
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { getLogicFunctionBaseFolderPath } from 'src/engine/metadata-modules/logic-function/utils/get-logic-function-base-folder-path.util';
import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
import { DeleteLogicFunctionAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/logic-function/types/workspace-migration-logic-function-action.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
@@ -13,8 +13,8 @@ import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-mana
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function-executor/drivers/utils/lambda-build-directory-manager';
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function-executor/logic-function-executor.service';
import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager';
import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import {
@@ -22,11 +22,11 @@ import {
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 { getLogicFunctionBaseFolderPath } from 'src/engine/metadata-modules/logic-function/utils/get-logic-function-base-folder-path.util';
import { getLogicFunctionBaseFolderPath } from 'src/engine/core-modules/logic-function/logic-function-build/utils/get-logic-function-base-folder-path.util';
import { UpdateLogicFunctionAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/logic-function/types/workspace-migration-logic-function-action.type';
import { WorkspaceMigrationActionRunnerArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/types/workspace-migration-action-runner-args.type';
import { fromFlatEntityPropertiesUpdatesToPartialFlatEntity } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/utils/from-flat-entity-properties-updates-to-partial-flat-entity';
import { LogicFunctionBuildService } from 'src/engine/metadata-modules/logic-function-build/logic-function-build.service';
import { LogicFunctionBuildService } from 'src/engine/core-modules/logic-function/logic-function-build/services/logic-function-build.service';
@Injectable()
export class UpdateLogicFunctionActionHandlerService extends WorkspaceMigrationRunnerActionHandler(
@@ -69,13 +69,11 @@ import { UpdateViewGroupActionHandlerService } from 'src/engine/workspace-manage
import { CreateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view/services/create-view-action-handler.service';
import { DeleteViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view/services/delete-view-action-handler.service';
import { UpdateViewActionHandlerService } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/view/services/update-view-action-handler.service';
import { LogicFunctionBuildModule } from 'src/engine/metadata-modules/logic-function-build/logic-function-build.module';
@Module({
imports: [
TypeOrmModule.forFeature([ApplicationEntity]),
WorkspaceSchemaManagerModule,
LogicFunctionBuildModule,
],
providers: [
CreateFieldActionHandlerService,
@@ -15,7 +15,7 @@ import { Repository } from 'typeorm';
import { v4 } from 'uuid';
import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util';
import { SEED_PROJECT_INPUT_SCHEMA } from 'src/engine/core-modules/logic-function-executor/drivers/constants/seed-project-input-schema';
import { SEED_PROJECT_INPUT_SCHEMA } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/seed-project-input-schema';
import { type WorkflowStepPositionInput } from 'src/engine/core-modules/workflow/dtos/update-workflow-step-position-input.dto';
import { AiAgentRoleService } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service';
import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';