Rename serverlessFunction to logicFunction (#17494)

## Summary

Rename "Serverless Function" to "Logic Function" across the codebase for
clearer naming.

### Environment Variable Changes

| Old | New |
|-----|-----|
| `SERVERLESS_TYPE` | `LOGIC_FUNCTION_TYPE` |
| `SERVERLESS_LAMBDA_REGION` | `LOGIC_FUNCTION_LAMBDA_REGION` |
| `SERVERLESS_LAMBDA_ROLE` | `LOGIC_FUNCTION_LAMBDA_ROLE` |
| `SERVERLESS_LAMBDA_SUBHOSTING_URL` |
`LOGIC_FUNCTION_LAMBDA_SUBHOSTING_URL` |
| `SERVERLESS_LAMBDA_ACCESS_KEY_ID` |
`LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID` |
| `SERVERLESS_LAMBDA_SECRET_ACCESS_KEY` |
`LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY` |

### Breaking Changes

- Environment variables must be updated in production deployments
- Database migration renames `serverlessFunction` → `logicFunction`
tables
This commit is contained in:
Charles Bochet
2026-01-28 01:42:19 +01:00
committed by GitHub
parent 59d123d2b1
commit da6f1bbef3
351 changed files with 5054 additions and 5139 deletions
@@ -6,7 +6,7 @@ import { RecordPositionModule } from 'src/engine/core-modules/record-position/re
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { WorkflowCreateManyPostQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-many.post-query.hook';
import { WorkflowCreateManyPreQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-many.pre-query.hook';
import { WorkflowCreateOnePostQueryHook } from 'src/modules/workflow/common/query-hooks/workflow-create-one.post-query.hook';
@@ -37,7 +37,7 @@ import { WorkflowVersionValidationWorkspaceService } from 'src/modules/workflow/
@Module({
imports: [
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity]),
ServerlessFunctionModule,
LogicFunctionModule,
RecordPositionModule,
WorkspaceManyOrAllFlatEntityMapsCacheModule,
ObjectMetadataModule,
@@ -1,14 +1,14 @@
import { Module } from '@nestjs/common';
import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { WorkflowQueryHookModule } from 'src/modules/workflow/common/query-hooks/workflow-query-hook.module';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
@Module({
imports: [
WorkflowQueryHookModule,
ServerlessFunctionModule,
LogicFunctionModule,
WorkspaceManyOrAllFlatEntityMapsCacheModule,
],
providers: [WorkflowCommonWorkspaceService],
@@ -7,7 +7,7 @@ import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/typ
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { type WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
@@ -41,7 +41,7 @@ export type ObjectMetadataInfo = {
export class WorkflowCommonWorkspaceService {
constructor(
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
private readonly serverlessFunctionService: ServerlessFunctionService,
private readonly logicFunctionService: LogicFunctionService,
private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
) {}
@@ -226,7 +226,7 @@ export class WorkflowCommonWorkspaceService {
operation,
});
await this.handleServerlessFunctionSubEntities({
await this.handleLogicFunctionSubEntities({
workflowVersionRepository,
workflowId,
workspaceId,
@@ -292,7 +292,7 @@ export class WorkflowCommonWorkspaceService {
}
}
async handleServerlessFunctionSubEntities({
async handleLogicFunctionSubEntities({
workflowVersionRepository,
workflowId,
workspaceId,
@@ -315,21 +315,21 @@ export class WorkflowCommonWorkspaceService {
if (step.type === WorkflowActionType.CODE) {
switch (operation) {
case 'delete':
await this.serverlessFunctionService.deleteOneServerlessFunction({
id: step.settings.input.serverlessFunctionId,
await this.logicFunctionService.deleteOneLogicFunction({
id: step.settings.input.logicFunctionId,
workspaceId,
softDelete: true,
});
break;
case 'restore':
await this.serverlessFunctionService.restoreOneServerlessFunction(
step.settings.input.serverlessFunctionId,
await this.logicFunctionService.restoreOneLogicFunction(
step.settings.input.logicFunctionId,
workspaceId,
);
break;
case 'destroy':
await this.serverlessFunctionService.deleteOneServerlessFunction({
id: step.settings.input.serverlessFunctionId,
await this.logicFunctionService.deleteOneLogicFunction({
id: step.settings.input.logicFunctionId,
workspaceId,
softDelete: false,
});
@@ -98,9 +98,9 @@ describe('computeWorkflowVersionStepChanges', () => {
type: WorkflowActionType.CODE,
settings: {
input: {
serverlessFunctionId: '',
serverlessFunctionVersion: '',
serverlessFunctionInput: {},
logicFunctionId: '',
logicFunctionVersion: '',
logicFunctionInput: {},
},
errorHandlingOptions: {
continueOnFailure: { value: false },
@@ -160,7 +160,7 @@ export class WorkflowSchemaWorkspaceService {
),
) as OutputSchema;
}
case WorkflowActionType.CODE: // StepOutput schema is computed on serverlessFunction draft execution
case WorkflowActionType.CODE: // StepOutput schema is computed on logicFunction draft execution
default:
return {};
}
@@ -6,9 +6,9 @@ import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/ag
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { ServerlessFunctionRuntime } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import { type FlatServerlessFunction } from 'src/engine/metadata-modules/serverless-function/types/flat-serverless-function.type';
import { LogicFunctionRuntime } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service';
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import { WorkflowCommonWorkspaceService } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
@@ -23,7 +23,7 @@ const mockWorkspaceId = 'workspace-id';
describe('WorkflowVersionStepOperationsWorkspaceService', () => {
let service: WorkflowVersionStepOperationsWorkspaceService;
let globalWorkspaceOrmManager: jest.Mocked<GlobalWorkspaceOrmManager>;
let serverlessFunctionService: jest.Mocked<ServerlessFunctionService>;
let logicFunctionService: jest.Mocked<LogicFunctionService>;
let agentRepository: jest.Mocked<any>;
let roleTargetRepository: jest.Mocked<any>;
let roleRepository: jest.Mocked<any>;
@@ -33,13 +33,13 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
let workspaceCacheService: jest.Mocked<WorkspaceCacheService>;
beforeEach(async () => {
serverlessFunctionService = {
createOneServerlessFunction: jest.fn(),
hasServerlessFunctionPublishedVersion: jest.fn(),
deleteOneServerlessFunction: jest.fn(),
duplicateServerlessFunction: jest.fn(),
logicFunctionService = {
createOneLogicFunction: jest.fn(),
hasLogicFunctionPublishedVersion: jest.fn(),
deleteOneLogicFunction: jest.fn(),
duplicateLogicFunction: jest.fn(),
createDraftFromPublishedVersion: jest.fn(),
} as unknown as jest.Mocked<ServerlessFunctionService>;
} as unknown as jest.Mocked<LogicFunctionService>;
agentRepository = {
findOne: jest.fn(),
@@ -83,8 +83,8 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
useValue: globalWorkspaceOrmManager,
},
{
provide: ServerlessFunctionService,
useValue: serverlessFunctionService,
provide: LogicFunctionService,
useValue: logicFunctionService,
},
{
provide: getRepositoryToken(AgentEntity),
@@ -121,7 +121,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
});
describe('runWorkflowVersionStepDeletionSideEffects', () => {
it('should delete serverless function when deleting code step', async () => {
it('should delete logic function when deleting code step', async () => {
const step = {
id: 'step-id',
name: 'Code Step',
@@ -130,8 +130,8 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
nextStepIds: [],
settings: {
input: {
serverlessFunctionId: 'function-id',
serverlessFunctionVersion: 'v1',
logicFunctionId: 'function-id',
logicFunctionVersion: 'v1',
},
outputSchema: {},
errorHandlingOptions: {
@@ -141,7 +141,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
},
} as unknown as WorkflowAction;
serverlessFunctionService.hasServerlessFunctionPublishedVersion.mockResolvedValue(
logicFunctionService.hasLogicFunctionPublishedVersion.mockResolvedValue(
false,
);
@@ -150,9 +150,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
workspaceId: mockWorkspaceId,
});
expect(
serverlessFunctionService.deleteOneServerlessFunction,
).toHaveBeenCalledWith({
expect(logicFunctionService.deleteOneLogicFunction).toHaveBeenCalledWith({
id: 'function-id',
workspaceId: mockWorkspaceId,
softDelete: false,
@@ -238,8 +236,8 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
});
describe('runStepCreationSideEffectsAndBuildStep', () => {
it('should create code step with serverless function', async () => {
const mockFlatServerlessFunction: FlatServerlessFunction = {
it('should create code step with logic function', async () => {
const mockFlatLogicFunction: FlatLogicFunction = {
id: 'new-function-id',
name: 'Test Function',
description: 'Test Description',
@@ -249,7 +247,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
runtime: ServerlessFunctionRuntime.NODE22,
runtime: LogicFunctionRuntime.NODE22,
timeoutSeconds: 30,
sourceHandlerPath: 'src/index.ts',
builtHandlerPath: 'index.mjs',
@@ -257,7 +255,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
checksum: null,
toolInputSchema: null,
isTool: false,
serverlessFunctionLayerId: 'layer-id',
logicFunctionLayerId: 'layer-id',
universalIdentifier: 'universal-id',
applicationId: 'application-id',
cronTriggerSettings: null,
@@ -265,8 +263,8 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
httpRouteTriggerSettings: null,
};
serverlessFunctionService.createOneServerlessFunction.mockResolvedValue(
mockFlatServerlessFunction,
logicFunctionService.createOneLogicFunction.mockResolvedValue(
mockFlatLogicFunction,
);
const result = await service.runStepCreationSideEffectsAndBuildStep({
@@ -279,16 +277,14 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
const codeResult = result.builtStep as unknown as {
settings: {
input: {
serverlessFunctionId: string;
serverlessFunctionVersion: string;
logicFunctionId: string;
logicFunctionVersion: string;
};
};
};
expect(codeResult.settings.input.serverlessFunctionId).toBe(
'new-function-id',
);
expect(codeResult.settings.input.serverlessFunctionVersion).toBe('draft');
expect(codeResult.settings.input.logicFunctionId).toBe('new-function-id');
expect(codeResult.settings.input.logicFunctionVersion).toBe('draft');
});
it('should create form step', async () => {
@@ -304,7 +300,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
});
describe('createStepForDuplicate', () => {
it('should duplicate code step with new serverless function', async () => {
it('should duplicate code step with new logic function', async () => {
const originalStep = {
id: 'original-id',
type: WorkflowActionType.CODE,
@@ -312,14 +308,14 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
valid: true,
settings: {
input: {
serverlessFunctionId: 'function-id',
serverlessFunctionVersion: 'v1',
logicFunctionId: 'function-id',
logicFunctionVersion: 'v1',
},
},
nextStepIds: ['next-step'],
} as unknown as WorkflowAction;
const mockNewFlatServerlessFunction: FlatServerlessFunction = {
const mockNewFlatLogicFunction: FlatLogicFunction = {
id: 'new-function-id',
name: 'Test Function',
description: 'Test Description',
@@ -329,7 +325,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
deletedAt: null,
runtime: ServerlessFunctionRuntime.NODE22,
runtime: LogicFunctionRuntime.NODE22,
timeoutSeconds: 30,
sourceHandlerPath: 'src/index.ts',
builtHandlerPath: 'index.mjs',
@@ -337,7 +333,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
checksum: null,
toolInputSchema: null,
isTool: false,
serverlessFunctionLayerId: 'layer-id',
logicFunctionLayerId: 'layer-id',
universalIdentifier: 'universal-id',
applicationId: 'application-id',
cronTriggerSettings: null,
@@ -345,8 +341,8 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
httpRouteTriggerSettings: null,
};
serverlessFunctionService.duplicateServerlessFunction.mockResolvedValue(
mockNewFlatServerlessFunction,
logicFunctionService.duplicateLogicFunction.mockResolvedValue(
mockNewFlatLogicFunction,
);
const clonedStep = await service.cloneStep({
@@ -362,16 +358,14 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => {
const codeResult = duplicateStep as unknown as {
settings: {
input: {
serverlessFunctionId: string;
serverlessFunctionVersion: string;
logicFunctionId: string;
logicFunctionVersion: string;
};
};
};
expect(codeResult.settings.input.serverlessFunctionId).toBe(
'new-function-id',
);
expect(codeResult.settings.input.serverlessFunctionVersion).toBe('draft');
expect(codeResult.settings.input.logicFunctionId).toBe('new-function-id');
expect(codeResult.settings.input.logicFunctionVersion).toBe('draft');
expect(duplicateStep.nextStepIds).toEqual([]);
});
@@ -39,9 +39,9 @@ describe('insertStep', () => {
type: WorkflowActionType.CODE,
settings: {
input: {
serverlessFunctionId: 'test',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'test',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -31,9 +31,9 @@ describe('removeStep', () => {
type: WorkflowActionType.CODE,
settings: {
input: {
serverlessFunctionId: 'test',
serverlessFunctionVersion: '1.0.0',
serverlessFunctionInput: {},
logicFunctionId: 'test',
logicFunctionVersion: '1.0.0',
logicFunctionInput: {},
},
outputSchema: {},
errorHandlingOptions: {
@@ -15,14 +15,14 @@ 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/serverless/drivers/constants/seed-project-input-schema';
import { SEED_PROJECT_INPUT_SCHEMA } from 'src/engine/core-modules/logic-function-executor/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';
import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
@@ -62,7 +62,7 @@ const ITERATOR_EMPTY_STEP_POSITION_OFFSET = {
export class WorkflowVersionStepOperationsWorkspaceService {
constructor(
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
private readonly serverlessFunctionService: ServerlessFunctionService,
private readonly logicFunctionService: LogicFunctionService,
@InjectRepository(AgentEntity)
private readonly agentRepository: Repository<AgentEntity>,
@InjectRepository(RoleTargetEntity)
@@ -84,13 +84,13 @@ export class WorkflowVersionStepOperationsWorkspaceService {
switch (step.type) {
case WorkflowActionType.CODE: {
if (
!(await this.serverlessFunctionService.hasServerlessFunctionPublishedVersion(
step.settings.input.serverlessFunctionId,
!(await this.logicFunctionService.hasLogicFunctionPublishedVersion(
step.settings.input.logicFunctionId,
workspaceId,
))
) {
await this.serverlessFunctionService.deleteOneServerlessFunction({
id: step.settings.input.serverlessFunctionId,
await this.logicFunctionService.deleteOneLogicFunction({
id: step.settings.input.logicFunctionId,
workspaceId,
softDelete: false,
});
@@ -154,16 +154,16 @@ export class WorkflowVersionStepOperationsWorkspaceService {
switch (type) {
case WorkflowActionType.CODE: {
const newServerlessFunction =
await this.serverlessFunctionService.createOneServerlessFunction(
const newLogicFunction =
await this.logicFunctionService.createOneLogicFunction(
{
name: 'A Serverless Function Code Workflow Step',
name: 'A Logic Function Code Workflow Step',
description: '',
},
workspaceId,
);
if (!isDefined(newServerlessFunction)) {
if (!isDefined(newLogicFunction)) {
throw new WorkflowVersionStepException(
'Fail to create Code Step',
WorkflowVersionStepExceptionCode.CODE_STEP_FAILURE,
@@ -173,7 +173,7 @@ export class WorkflowVersionStepOperationsWorkspaceService {
return {
builtStep: {
...baseStep,
name: 'Code - Serverless Function',
name: 'Code - Logic Function',
type: WorkflowActionType.CODE,
settings: {
...BASE_STEP_DEFINITION,
@@ -187,9 +187,9 @@ export class WorkflowVersionStepOperationsWorkspaceService {
_outputSchemaType: 'LINK',
},
input: {
serverlessFunctionId: newServerlessFunction.id,
serverlessFunctionVersion: 'draft',
serverlessFunctionInput: SEED_PROJECT_INPUT_SCHEMA,
logicFunctionId: newLogicFunction.id,
logicFunctionVersion: 'draft',
logicFunctionInput: SEED_PROJECT_INPUT_SCHEMA,
},
},
},
@@ -615,10 +615,10 @@ export class WorkflowVersionStepOperationsWorkspaceService {
switch (step.type) {
case WorkflowActionType.CODE: {
const newServerlessFunction =
await this.serverlessFunctionService.duplicateServerlessFunction({
id: step.settings.input.serverlessFunctionId,
version: step.settings.input.serverlessFunctionVersion,
const newLogicFunction =
await this.logicFunctionService.duplicateLogicFunction({
id: step.settings.input.logicFunctionId,
version: step.settings.input.logicFunctionVersion,
workspaceId,
});
@@ -631,8 +631,8 @@ export class WorkflowVersionStepOperationsWorkspaceService {
...step.settings,
input: {
...step.settings.input,
serverlessFunctionId: newServerlessFunction.id,
serverlessFunctionVersion: 'draft',
logicFunctionId: newLogicFunction.id,
logicFunctionVersion: 'draft',
},
},
};
@@ -890,9 +890,9 @@ export class WorkflowVersionStepOperationsWorkspaceService {
}): Promise<WorkflowAction> {
switch (step.type) {
case WorkflowActionType.CODE: {
await this.serverlessFunctionService.createDraftFromPublishedVersion({
id: step.settings.input.serverlessFunctionId,
version: step.settings.input.serverlessFunctionVersion,
await this.logicFunctionService.createDraftFromPublishedVersion({
id: step.settings.input.logicFunctionId,
version: step.settings.input.logicFunctionVersion,
workspaceId,
});
@@ -902,7 +902,7 @@ export class WorkflowVersionStepOperationsWorkspaceService {
...step.settings,
input: {
...step.settings.input,
serverlessFunctionVersion: 'draft',
logicFunctionVersion: 'draft',
},
},
};
@@ -7,7 +7,7 @@ import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/ag
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
import { WorkflowCommonModule } from 'src/modules/workflow/common/workflow-common.module';
import { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.module';
@@ -21,7 +21,7 @@ import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workfl
@Module({
imports: [
WorkflowSchemaModule,
ServerlessFunctionModule,
LogicFunctionModule,
WorkflowCommonModule,
AiAgentRoleModule,
WorkspaceCacheModule,
@@ -4,7 +4,7 @@ import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { RecordPositionModule } from 'src/engine/core-modules/record-position/record-position.module';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { WorkflowSchemaModule } from 'src/modules/workflow/workflow-builder/workflow-schema/workflow-schema.module';
import { WorkflowVersionStepModule } from 'src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module';
import { WorkflowVersionWorkspaceService } from 'src/modules/workflow/workflow-builder/workflow-version/workflow-version.workspace-service';
@@ -12,7 +12,7 @@ import { WorkflowVersionWorkspaceService } from 'src/modules/workflow/workflow-b
@Module({
imports: [
WorkflowSchemaModule,
ServerlessFunctionModule,
LogicFunctionModule,
WorkflowVersionStepModule,
NestjsQueryTypeOrmModule.forFeature([ObjectMetadataEntity]),
RecordPositionModule,
@@ -98,10 +98,10 @@ export class WorkflowExecutionContextService {
// Use the application's role if set, otherwise fall back to admin role
// In the future we should probably assign the Admin role to the Standard Application
let roleId = application.defaultServerlessFunctionRoleId;
let roleId = application.defaultLogicFunctionRoleId;
if (!isDefined(roleId)) {
// Fallback: Look up admin role for existing workspaces without defaultServerlessFunctionRoleId
// Fallback: Look up admin role for existing workspaces without defaultLogicFunctionRoleId
const adminRole = await this.roleService.getRoleByUniversalIdentifier({
universalIdentifier: ADMIN_ROLE.standardId,
workspaceId,
@@ -119,7 +119,7 @@ export class WorkflowExecutionContextService {
apiKey: null,
application: {
...application,
defaultServerlessFunctionRoleId: roleId,
defaultLogicFunctionRoleId: roleId,
},
workspace,
workspaceMemberId: undefined,
@@ -242,9 +242,9 @@ describe('shouldExecuteStep', () => {
type: WorkflowActionType.CODE,
settings: {
input: {
serverlessFunctionId: 'mock-function-id',
serverlessFunctionVersion: 'mock-function-version',
serverlessFunctionInput: {},
logicFunctionId: 'mock-function-id',
logicFunctionVersion: 'mock-function-version',
logicFunctionInput: {},
},
errorHandlingOptions: {
continueOnFailure: { value: false },
@@ -16,9 +16,9 @@ describe('shouldSkipStepExecution', () => {
type: WorkflowActionType.CODE,
settings: {
input: {
serverlessFunctionId: 'mock-function-id',
serverlessFunctionVersion: 'mock-function-version',
serverlessFunctionInput: {},
logicFunctionId: 'mock-function-id',
logicFunctionVersion: 'mock-function-version',
logicFunctionInput: {},
},
errorHandlingOptions: {
continueOnFailure: { value: false },
@@ -1,10 +1,10 @@
import { Module } from '@nestjs/common';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { CodeWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action';
@Module({
imports: [ServerlessFunctionModule],
imports: [LogicFunctionModule],
providers: [CodeWorkflowAction],
exports: [CodeWorkflowAction],
})
@@ -4,7 +4,7 @@ import { resolveInput } from 'twenty-shared/utils';
import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service';
import {
WorkflowStepExecutorException,
WorkflowStepExecutorExceptionCode,
@@ -17,9 +17,7 @@ import { type WorkflowCodeActionInput } from 'src/modules/workflow/workflow-exec
@Injectable()
export class CodeWorkflowAction implements WorkflowAction {
constructor(
private readonly serverlessFunctionService: ServerlessFunctionService,
) {}
constructor(private readonly logicFunctionService: LogicFunctionService) {}
async execute({
currentStepId,
@@ -47,13 +45,12 @@ export class CodeWorkflowAction implements WorkflowAction {
try {
const { workspaceId } = runInfo;
const result =
await this.serverlessFunctionService.executeOneServerlessFunction({
id: workflowActionInput.serverlessFunctionId,
workspaceId,
payload: workflowActionInput.serverlessFunctionInput,
version: workflowActionInput.serverlessFunctionVersion,
});
const result = await this.logicFunctionService.executeOneLogicFunction({
id: workflowActionInput.logicFunctionId,
workspaceId,
payload: workflowActionInput.logicFunctionInput,
version: workflowActionInput.logicFunctionVersion,
});
if (result.error) {
return { error: result.error.errorMessage };
@@ -1,7 +1,7 @@
export type WorkflowCodeActionInput = {
serverlessFunctionId: string;
serverlessFunctionVersion: string;
serverlessFunctionInput: {
logicFunctionId: string;
logicFunctionVersion: string;
logicFunctionInput: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
};
@@ -51,9 +51,9 @@ describe('shouldExecuteIteratorStep', () => {
type: WorkflowActionType.CODE,
settings: {
input: {
serverlessFunctionId: 'mock-function-id',
serverlessFunctionVersion: 'mock-function-version',
serverlessFunctionInput: {},
logicFunctionId: 'mock-function-id',
logicFunctionVersion: 'mock-function-version',
logicFunctionInput: {},
},
errorHandlingOptions: {
continueOnFailure: { value: false },
@@ -51,9 +51,9 @@ describe('shouldSkipIteratorStepExecution', () => {
type: WorkflowActionType.CODE,
settings: {
input: {
serverlessFunctionId: 'mock-function-id',
serverlessFunctionVersion: 'mock-function-version',
serverlessFunctionInput: {},
logicFunctionId: 'mock-function-id',
logicFunctionVersion: 'mock-function-version',
logicFunctionInput: {},
},
errorHandlingOptions: {
continueOnFailure: { value: false },
@@ -2,8 +2,8 @@ import { Test, type TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
import { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { WorkflowVersionStatus } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity';
import { WorkflowStatus } from 'src/modules/workflow/common/standard-objects/workflow.workspace-entity';
@@ -52,8 +52,8 @@ describe('WorkflowStatusesUpdate', () => {
.mockImplementation((fn: () => any, _authContext?: any) => fn()),
};
const mockServerlessFunctionService = {
publishOneServerlessFunctionOrFail: jest.fn(),
const mockLogicFunctionService = {
publishOneLogicFunctionOrFail: jest.fn(),
findOneOrFail: jest.fn(),
};
@@ -66,8 +66,8 @@ describe('WorkflowStatusesUpdate', () => {
useValue: mockGlobalWorkspaceOrmManager,
},
{
provide: ServerlessFunctionService,
useValue: mockServerlessFunctionService,
provide: LogicFunctionService,
useValue: mockLogicFunctionService,
},
{
provide: getRepositoryToken(ObjectMetadataEntity),
@@ -78,7 +78,7 @@ describe('WorkflowStatusesUpdate', () => {
},
},
{
provide: getRepositoryToken(ServerlessFunctionEntity),
provide: getRepositoryToken(LogicFunctionEntity),
useValue: {
findOneOrFail: jest.fn().mockResolvedValue({
latestVersion: 'v2',
@@ -193,7 +193,7 @@ describe('WorkflowStatusesUpdate', () => {
expect(mockWorkflowRepository.update).toHaveBeenCalledTimes(0);
});
test('when WorkflowVersionStatus.DRAFT to WorkflowVersionStatus.ACTIVE, should activate and publish serverless functions', async () => {
test('when WorkflowVersionStatus.DRAFT to WorkflowVersionStatus.ACTIVE, should activate and publish logic functions', async () => {
const event: WorkflowVersionBatchEvent = {
workspaceId: '1',
type: WorkflowVersionEventType.STATUS_UPDATE,
@@ -220,15 +220,15 @@ describe('WorkflowStatusesUpdate', () => {
type: 'CODE',
settings: {
input: {
serverlessFunctionId: 'serverless-1',
logicFunctionId: 'logic-function-1',
},
},
},
],
};
const mockServerlessFunction = {
id: 'serverless-1',
const mockLogicFunction = {
id: 'logic-function-1',
latestVersion: 'v2',
};
@@ -239,11 +239,11 @@ describe('WorkflowStatusesUpdate', () => {
mockWorkflowVersionRepository.find.mockResolvedValue([
{ status: WorkflowVersionStatus.ACTIVE },
]);
mockServerlessFunctionService.findOneOrFail.mockResolvedValue(
mockServerlessFunction,
mockLogicFunctionService.findOneOrFail.mockResolvedValue(
mockLogicFunction,
);
mockServerlessFunctionService.publishOneServerlessFunctionOrFail.mockResolvedValue(
mockServerlessFunction,
mockLogicFunctionService.publishOneLogicFunctionOrFail.mockResolvedValue(
mockLogicFunction,
);
await job.handle(event);
@@ -253,16 +253,16 @@ describe('WorkflowStatusesUpdate', () => {
mockWorkflowVersionRepository.findOneOrFail,
).toHaveBeenCalledTimes(1);
expect(
mockServerlessFunctionService.publishOneServerlessFunctionOrFail,
).toHaveBeenCalledWith('serverless-1', '1');
mockLogicFunctionService.publishOneLogicFunctionOrFail,
).toHaveBeenCalledWith('logic-function-1', '1');
expect(mockWorkflowVersionRepository.update).toHaveBeenCalledWith('1', {
steps: [
{
type: 'CODE',
settings: {
input: {
serverlessFunctionId: 'serverless-1',
serverlessFunctionVersion: 'v2',
logicFunctionId: 'logic-function-1',
logicFunctionVersion: 'v2',
},
},
},
@@ -7,7 +7,7 @@ import { In } from 'typeorm';
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 { ServerlessFunctionService } from 'src/engine/metadata-modules/serverless-function/serverless-function.service';
import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/logic-function.service';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
import { type WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util';
@@ -71,7 +71,7 @@ export class WorkflowStatusesUpdateJob {
constructor(
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
private readonly serverlessFunctionService: ServerlessFunctionService,
private readonly logicFunctionService: LogicFunctionService,
) {}
@Process(WorkflowStatusesUpdateJob.name)
@@ -154,7 +154,7 @@ export class WorkflowStatusesUpdateJob {
);
}
private async handlePublishServerlessFunction({
private async handlePublishLogicFunction({
statusUpdate,
workspaceId,
workflowVersion,
@@ -179,23 +179,23 @@ export class WorkflowStatusesUpdateJob {
const newStep = { ...step };
if (step.type === WorkflowActionType.CODE) {
const serverlessFunction =
await this.serverlessFunctionService.publishOneServerlessFunctionOrFail(
step.settings.input.serverlessFunctionId,
const logicFunction =
await this.logicFunctionService.publishOneLogicFunctionOrFail(
step.settings.input.logicFunctionId,
workspaceId,
);
const newStepSettings = { ...step.settings };
if (!isDefined(serverlessFunction.latestVersion)) {
if (!isDefined(logicFunction.latestVersion)) {
throw new WorkflowVersionStepException(
`Fail to publish serverless function ${serverlessFunction.id}. Latest version is null`,
`Fail to publish logic function ${logicFunction.id}. Latest version is null`,
WorkflowVersionStepExceptionCode.CODE_STEP_FAILURE,
);
}
newStepSettings.input.serverlessFunctionVersion =
serverlessFunction.latestVersion;
newStepSettings.input.logicFunctionVersion =
logicFunction.latestVersion;
newStep.settings = newStepSettings;
}
@@ -240,7 +240,7 @@ export class WorkflowStatusesUpdateJob {
where: { id: statusUpdate.workflowVersionId },
});
await this.handlePublishServerlessFunction({
await this.handlePublishLogicFunction({
workflowVersion,
workflowVersionRepository,
workspaceId,
@@ -2,17 +2,17 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
import { ServerlessFunctionEntity } from 'src/engine/metadata-modules/serverless-function/serverless-function.entity';
import { ServerlessFunctionModule } from 'src/engine/metadata-modules/serverless-function/serverless-function.module';
import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module';
import { WorkflowStatusesUpdateJob } from 'src/modules/workflow/workflow-status/jobs/workflow-statuses-update.job';
import { WorkflowVersionStatusListener } from 'src/modules/workflow/workflow-status/listeners/workflow-version-status.listener';
@Module({
imports: [
ServerlessFunctionModule,
LogicFunctionModule,
WorkspaceEventEmitterModule,
TypeOrmModule.forFeature([ObjectMetadataEntity, ServerlessFunctionEntity]),
TypeOrmModule.forFeature([ObjectMetadataEntity, LogicFunctionEntity]),
],
providers: [WorkflowStatusesUpdateJob, WorkflowVersionStatusListener],
})