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:
@@ -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,
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
+1
-1
@@ -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({
|
||||
|
||||
-30
@@ -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
-1
@@ -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],
|
||||
+2
-2
@@ -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
-1
@@ -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,
|
||||
+5
-5
@@ -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';
|
||||
+6
-6
@@ -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;
|
||||
+12
-13
@@ -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
-1
@@ -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 = {
|
||||
+1
-1
@@ -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
-1
@@ -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, {
|
||||
+1
-1
@@ -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);
|
||||
+2
-2
@@ -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;
|
||||
+1
-1
@@ -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);
|
||||
+1
-1
@@ -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);
|
||||
+1
-1
@@ -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';
|
||||
|
||||
+3
-3
@@ -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(
|
||||
+4
-3
@@ -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> => {
|
||||
+2
-2
@@ -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',
|
||||
+26
@@ -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 {}
|
||||
+261
@@ -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),
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
+16
@@ -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 {}
|
||||
+1
-1
@@ -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';
|
||||
|
||||
+6
-4
@@ -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 ?? {},
|
||||
}),
|
||||
),
|
||||
);
|
||||
+29
@@ -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 {}
|
||||
+2
-1
@@ -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',
|
||||
+1
-1
@@ -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';
|
||||
|
||||
+2
-2
@@ -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
-1
@@ -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';
|
||||
+1
-1
@@ -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';
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
+10
-9
@@ -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;
|
||||
+1
-1
@@ -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', () => {
|
||||
-8
@@ -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);
|
||||
}
|
||||
}
|
||||
+35
@@ -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';
|
||||
|
||||
-14
@@ -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 {}
|
||||
-12
@@ -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 {}
|
||||
+2
-9
@@ -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 {}
|
||||
|
||||
+1
-1
@@ -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
@@ -1 +0,0 @@
|
||||
export const LOGIC_FUNCTION_PUBLISHED = 'logic_function_published';
|
||||
-9
@@ -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;
|
||||
}
|
||||
-4
@@ -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,
|
||||
],
|
||||
|
||||
+31
-205
@@ -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>;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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)
|
||||
|
||||
-14
@@ -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 {}
|
||||
|
||||
+4
-4
@@ -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(
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
|
||||
+4
-4
@@ -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(
|
||||
|
||||
-2
@@ -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,
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user